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

Version Description

= v140816 =

(Maintenance Release) Upgrade immediately.

Download this release

Release Info

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

Code changes from version 140725 to 140816

Files changed (41) hide show
  1. checksum.txt +1 -1
  2. includes/classes/access-cap-times.inc.php +1 -1
  3. includes/classes/auto-eots.inc.php +1 -0
  4. includes/classes/files-in.inc.php +1308 -1276
  5. includes/classes/ip-restrictions.inc.php +7 -8
  6. includes/classes/list-servers.inc.php +32 -0
  7. includes/classes/login-customizations.inc.php +4 -3
  8. includes/classes/login-redirects.inc.php +198 -184
  9. includes/classes/menu-pages.inc.php +677 -732
  10. includes/classes/mo-page.inc.php +1 -1
  11. includes/classes/pages-sp.inc.php +96 -104
  12. includes/classes/pages.inc.php +94 -103
  13. includes/classes/paypal-return-in-subscr-modify-w-level.inc.php +4 -4
  14. includes/classes/paypal-return-in-subscr-or-wa-w-level.inc.php +379 -374
  15. includes/classes/paypal-return-in-wa-ccaps-wo-level.inc.php +4 -4
  16. includes/classes/paypal-return-in-web-accept-sp.inc.php +4 -4
  17. includes/classes/posts-sp.inc.php +122 -107
  18. includes/classes/posts.inc.php +119 -107
  19. includes/classes/querys.inc.php +378 -372
  20. includes/classes/registration-times.inc.php +1 -1
  21. includes/classes/return-templates.inc.php +65 -69
  22. includes/classes/roles-caps.inc.php +155 -155
  23. includes/classes/ruris.inc.php +94 -95
  24. includes/classes/sc-files-in.inc.php +311 -143
  25. includes/classes/utils-arrays.inc.php +1 -1
  26. includes/classes/utils-conds.inc.php +29 -0
  27. includes/classes/utils-gets.inc.php +391 -333
  28. includes/classes/utils-users.inc.php +3 -11
  29. includes/functions/class-autoloader.inc.php +75 -76
  30. includes/menu-pages/down-ops.inc.php +656 -649
  31. includes/menu-pages/gen-ops.inc.php +8 -1
  32. includes/menu-pages/integrations.inc.php +72 -74
  33. includes/menu-pages/menu-pages-s-min.js +1 -1
  34. includes/menu-pages/menu-pages-s.js +20 -19
  35. includes/menu-pages/res-ops.inc.php +1 -1
  36. includes/templates/players/jwplayer-v6-rtmp-only.php +1 -4
  37. includes/templates/players/jwplayer-v6-rtmp.php +1 -5
  38. includes/templates/players/jwplayer-v6.php +1 -4
  39. includes/translations/s2member.pot +1905 -1907
  40. readme.txt +33 -4
  41. s2member.php +4 -4
checksum.txt CHANGED
@@ -1 +1 @@
1
- a5a97b396b6173a3fb461b92da759019
1
+ fe5b4d8fea0ad64e6be257a6b6bba04c
includes/classes/access-cap-times.inc.php CHANGED
@@ -211,7 +211,7 @@ if(!class_exists('c_ws_plugin__s2member_access_cap_times'))
211
212
// $update_ac_times = empty($ac_times) ? FALSE : TRUE;
213
$ac_times_min = !empty($ac_times) ? min(array_keys($ac_times)) : 0;
214
- if(($r_time = c_ws_plugin__s2member_registration_times::registration_time()) && (empty($ac_times_min) || $r_time < $ac_times_min))
215
$ac_times[number_format(($r_time += .0001), 4, '.', '')] = 'level0';
216
217
if(is_array($pr_times = get_user_option('s2member_paid_registration_times', $user_id)))
211
212
// $update_ac_times = empty($ac_times) ? FALSE : TRUE;
213
$ac_times_min = !empty($ac_times) ? min(array_keys($ac_times)) : 0;
214
+ if(($r_time = c_ws_plugin__s2member_registration_times::registration_time($user_id)) && (empty($ac_times_min) || $r_time < $ac_times_min))
215
$ac_times[number_format(($r_time += .0001), 4, '.', '')] = 'level0';
216
217
if(is_array($pr_times = get_user_option('s2member_paid_registration_times', $user_id)))
includes/classes/auto-eots.inc.php CHANGED
@@ -169,6 +169,7 @@ if (!class_exists ("c_ws_plugin__s2member_auto_eots"))
169
delete_user_option ($user_id, "s2member_auto_eot_time");
170
171
delete_user_option ($user_id, "s2member_file_download_access_log");
172
173
c_ws_plugin__s2member_user_notes::append_user_notes ($user_id, "Demoted by s2Member: " . date ("D M j, Y g:i a T"));
174
169
delete_user_option ($user_id, "s2member_auto_eot_time");
170
171
delete_user_option ($user_id, "s2member_file_download_access_log");
172
+ delete_user_option ($user_id, "s2member_authnet_payment_failures");
173
174
c_ws_plugin__s2member_user_notes::append_user_notes ($user_id, "Demoted by s2Member: " . date ("D M j, Y g:i a T"));
175
includes/classes/files-in.inc.php CHANGED
@@ -1,1411 +1,1443 @@
1
<?php
2
/**
3
- * File Download routines for s2Member (inner processing routines).
4
- *
5
- * Copyright: © 2009-2011
6
- * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
7
- * (coded in the USA)
8
- *
9
- * Released under the terms of the GNU General Public License.
10
- * You should have received a copy of the GNU General Public License,
11
- * along with this software. In the main directory, see: /licensing/
12
- * If not, see: {@link http://www.gnu.org/licenses/}.
13
- *
14
- * @package s2Member\Files
15
- * @since 3.5
16
- */
17
- if(realpath(__FILE__) === realpath($_SERVER["SCRIPT_FILENAME"]))
18
- exit("Do not access this file directly.");
19
-
20
- if(!class_exists("c_ws_plugin__s2member_files_in"))
21
{
22
/**
23
- * File Download routines for s2Member (inner processing routines).
24
- *
25
- * @package s2Member\Files
26
- * @since 3.5
27
- */
28
- class c_ws_plugin__s2member_files_in
29
{
30
- /**
31
- * Handles Download Access permissions.
32
- *
33
- * @package s2Member\Files
34
- * @since 3.5
35
- *
36
- * @attaches-to ``add_action("init");``
37
- * @also-called-by API Function {@link s2Member\API_Functions\s2member_file_download_url()}, w/ ``$create_file_download_url`` param.
38
- *
39
- * @param array $create_file_download_url Optional. If this function is called directly, we can pass arguments through this array.
40
- * Possible array elements: `file_download` *(required)*, `file_download_key`, `file_stream`, `file_inline`, `file_storage`, `file_remote`, `file_ssl`, `file_rewrite`, `file_rewrite_base`, `skip_confirmation`, `url_to_storage_source`, `count_against_user`, `check_user`.
41
- * @return null|str If called directly with ``$create_file_download_url``, returns a string with the URL, based on configuration.
42
- * Else, this function may exit script execution after serving a File Download.
43
- */
44
- public static function check_file_download_access($create_file_download_url = FALSE)
45
{
46
- foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$__v;
47
- do_action("ws_plugin__s2member_before_file_download_access", get_defined_vars());
48
- unset($__refs, $__v);
49
-
50
- $_g = !empty($_GET) ? $_GET : array();
51
- $_g = c_ws_plugin__s2member_utils_strings::trim_deep(stripslashes_deep($_g));
52
-
53
- $creating = /* Creating URL? */ (is_array($create = $create_file_download_url)) ? true : false;
54
- $serving = /* If NOT creating a File Download URL, we're serving one. */ (!$creating) ? true : false;
55
- $serving_range = $range = /* Default values (so these variables DO get defined at all times). */ false;
56
- if /* If we're serving, let's see if we're serving a byte-range request here. */($serving)
57
{
58
- $range = (string)@$_SERVER["HTTP_RANGE"];
59
- if(!$range && function_exists("apache_request_headers"))
60
- // Note: ``apache_request_headers()`` works in FastCGI too, starting w/ PHP v5.4.
61
- foreach((array)apache_request_headers() as $_header => $_value)
62
- if(is_string($_header) && strcasecmp($_header, "range") === 0)
63
- $range = $_value;
64
- if /* Serving a range? */($range)
65
- $serving_range = true;
66
- unset($_header, $_value);
67
}
68
- $req["file_download"] = ($creating) ? @$create["file_download"] : @$_g["s2member_file_download"];
69
- $req["file_download_key"] = ($creating) ? @$create["file_download_key"] : @$_g["s2member_file_download_key"];
70
-
71
- $req["file_stream"] = ($creating) ? @$create["file_stream"] : @$_g["s2member_file_stream"];
72
- $req["file_inline"] = ($creating) ? @$create["file_inline"] : @$_g["s2member_file_inline"];
73
- $req["file_storage"] = ($creating) ? @$create["file_storage"] : @$_g["s2member_file_storage"];
74
- $req["file_remote"] = ($creating) ? @$create["file_remote"] : @$_g["s2member_file_remote"];
75
- $req["file_ssl"] = ($creating) ? @$create["file_ssl"] : @$_g["s2member_file_ssl"];
76
-
77
- $req["file_rewrite"] = ($creating) ? @$create["file_rewrite"] : /* N/A. */ null;
78
- $req["file_rewrite_base"] = ($creating) ? @$create["file_rewrite_base"] : /* N/A. */ null;
79
-
80
- $req["skip_confirmation"] = ($creating) ? @$create["skip_confirmation"] : /* N/A. */ null;
81
- $req["url_to_storage_source"] = ($creating) ? @$create["url_to_storage_source"] : /* N/A. */ null;
82
- $req["count_against_user"] = ($creating) ? @$create["count_against_user"] : /* N/A. */ null;
83
- $req["check_user"] = ($creating) ? @$create["check_user"] : /* N/A. */ null;
84
85
- if($req["file_download"] && is_string($req["file_download"]) && ($req["file_download"] = trim($req["file_download"], "/")))
86
- if(strpos($req["file_download"], "..") === false && strpos(basename($req["file_download"]), ".") !== 0)
87
{
88
- $using_amazon_cf_storage = ((!$req["file_storage"] || strcasecmp((string)$req["file_storage"], "cf") === 0) && c_ws_plugin__s2member_utils_conds::using_amazon_cf_storage()) ? true : false;
89
- $using_amazon_s3_storage = ((!$req["file_storage"] || strcasecmp((string)$req["file_storage"], "s3") === 0) && c_ws_plugin__s2member_utils_conds::using_amazon_s3_storage()) ? true : false;
90
- $using_amazon_storage = /* Either? */ ($using_amazon_cf_storage || $using_amazon_s3_storage) ? true : false;
91
92
- $excluded = apply_filters("ws_plugin__s2member_check_file_download_access_excluded", false, get_defined_vars());
93
- $valid_file_download_key = ($req["file_download_key"] && is_string($req["file_download_key"]) && $creating && (!isset($req["check_user"]) || !filter_var($req["check_user"], FILTER_VALIDATE_BOOLEAN)) && (!isset($req["count_against_user"]) || !filter_var($req["count_against_user"], FILTER_VALIDATE_BOOLEAN))) ? true : false;
94
- $valid_file_download_key = (!$valid_file_download_key && $req["file_download_key"] && is_string($req["file_download_key"])) ? c_ws_plugin__s2member_files_in::check_file_download_key($req["file_download"], $req["file_download_key"]) : false;
95
- $checking_user = ($excluded || $valid_file_download_key || ($creating && (!isset($req["check_user"]) || !filter_var($req["check_user"], FILTER_VALIDATE_BOOLEAN)) && (!isset($req["count_against_user"]) || !filter_var($req["count_against_user"], FILTER_VALIDATE_BOOLEAN)))) ? false : true;
96
- $updating_user_counter = ($serving_range || !$checking_user || ($creating && (!isset($req["count_against_user"]) || !filter_var($req["count_against_user"], FILTER_VALIDATE_BOOLEAN)))) ? false : true;
97
98
- if( /* In either case, the following routines apply whenever we ARE ``$checking_user``. */($serving || $creating) && $checking_user)
99
- {
100
- if(!$using_amazon_storage && !file_exists($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"]."/".$req["file_download"]))
101
- {
102
- if /* We only need this section when/if we're actually serving. */($serving)
103
- {
104
- status_header(404);
105
- header("Content-Type: text/html; charset=UTF-8");
106
- while (@ob_end_clean ()); // Clean any existing output buffers.
107
- exit(_x('<strong>404: Sorry, file not found.</strong> Please contact Support for assistance.', "s2member-front", "s2member"));
108
- }
109
- else // Else return false.
110
- return false;
111
- }
112
113
- else if($req["file_download_key"] && is_string($req["file_download_key"]) && !$valid_file_download_key)
114
- {
115
- if /* We only need this section when/if we're actually serving. */($serving)
116
- {
117
- status_header(503);
118
- header("Content-Type: text/html; charset=UTF-8");
119
- while (@ob_end_clean ()); // Clean any existing output buffers.
120
- exit(_x('<strong>503 (Invalid Key):</strong> Sorry, your access to this file has expired. Please contact Support for assistance.', "s2member-front", "s2member"));
121
- }
122
- else // Else return false.
123
- return false;
124
- }
125
126
- else // Default behavior; check file download access against the current user.
127
- {
128
- if /* We only need remote functionality when/if we're actually serving. */($serving)
129
- if(!has_filter("ws_plugin__s2member_check_file_download_access_user", "c_ws_plugin__s2member_files_in::check_file_remote_authorization"))
130
- add_filter("ws_plugin__s2member_check_file_download_access_user", "c_ws_plugin__s2member_files_in::check_file_remote_authorization", 10, 2);
131
132
- if /* We only need remote functionality when/if we're actually serving. */($creating)
133
- if(has_filter("ws_plugin__s2member_check_file_download_access_user", "c_ws_plugin__s2member_files_in::check_file_remote_authorization"))
134
- remove_filter("ws_plugin__s2member_check_file_download_access_user", "c_ws_plugin__s2member_files_in::check_file_remote_authorization", 10, 2);
135
136
- if(!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
137
- {
138
- if /* We only need this section when/if we're actually serving. */($serving)
139
- {
140
- status_header(503);
141
- header("Content-Type: text/html; charset=UTF-8");
142
- while (@ob_end_clean ()); // Clean any existing output buffers.
143
- exit(_x('<strong>503: Basic File Downloads are NOT enabled yet.</strong> Please contact Support for assistance. If you are the site owner, please configure: <code>s2Member -› General Options -› Membership Options Page</code>.', "s2member-front", "s2member"));
144
- }
145
- else // Else return false.
146
- return false;
147
- }
148
149
- else if(($file_downloads_enabled_by_site_owner = $min_level_4_downloads = c_ws_plugin__s2member_files::min_level_4_downloads()) === false)
150
- {
151
- if /* We only need this section when/if we're actually serving. */($serving)
152
- {
153
- status_header(503);
154
- header("Content-Type: text/html; charset=UTF-8");
155
- while (@ob_end_clean ()); // Clean any existing output buffers.
156
- exit(_x('<strong>503: Basic File Downloads are NOT enabled yet.</strong> Please contact Support for assistance. If you are the site owner, please configure: <code>s2Member -› Download Options -› Basic Download Restrictions</code>.', "s2member-front", "s2member"));
157
- }
158
- else // Else return false.
159
- return false;
160
- }
161
-
162
- else if(!is_object($user = apply_filters("ws_plugin__s2member_check_file_download_access_user", ((is_user_logged_in()) ? wp_get_current_user() : false), get_defined_vars())) || empty($user->ID) || !($user_id = $user->ID) || !is_array($user_file_downloads = c_ws_plugin__s2member_files::user_downloads($user)) || (!$user->has_cap("administrator") && (!$user_file_downloads["allowed"] || !$user_file_downloads["allowed_days"])))
163
- {
164
- if(preg_match("/(?:^|\/)access[_\-]s2member[_\-]level([0-9]+)\//", $req["file_download"], $m) && strlen($req_level = $m[1]) && (!is_object($user) || empty($user->ID) || !$user->has_cap("access_s2member_level".$req_level)))
165
- {
166
- if /* We only need this section when/if we're actually serving. */($serving)
167
- c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */("file", $req["file_download"], "level", $req_level, $_SERVER["REQUEST_URI"]).exit();
168
-
169
- else // Else return false.
170
- return false;
171
- }
172
-
173
- else if(preg_match("/(?:^|\/)access[_\-]s2member[_\-]ccap[_\-](.+?)\//", $req["file_download"], $m) && strlen($req_ccap = preg_replace("/-/", "_", $m[1])) && (!is_object($user) || empty($user->ID) || !$user->has_cap("access_s2member_ccap_".$req_ccap)))
174
- {
175
- if /* We only need this section when/if we're actually serving. */($serving)
176
- c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */("file", $req["file_download"], "ccap", $req_ccap, $_SERVER["REQUEST_URI"]).exit();
177
-
178
- else // Else return false.
179
- return false;
180
- }
181
-
182
- else if /* We only need this section when/if we're actually serving. */($serving)
183
- c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */("file", $req["file_download"], "level", $min_level_4_downloads, $_SERVER["REQUEST_URI"]).exit();
184
-
185
- else // Else return false.
186
- return false;
187
- }
188
-
189
- else if(preg_match("/(?:^|\/)access[_\-]s2member[_\-]level([0-9]+)\//", $req["file_download"], $m) && strlen($req_level = $m[1]) && !$user->has_cap("access_s2member_level".$req_level))
190
- {
191
- if /* We only need this section when/if we're actually serving. */($serving)
192
- c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */("file", $req["file_download"], "level", $req_level, $_SERVER["REQUEST_URI"]).exit();
193
-
194
- else // Else return false.
195
- return false;
196
- }
197
-
198
- else if(preg_match("/(?:^|\/)access[_\-]s2member[_\-]ccap[_\-](.+?)\//", $req["file_download"], $m) && strlen($req_ccap = preg_replace("/-/", "_", $m[1])) && !$user->has_cap("access_s2member_ccap_".$req_ccap))
199
- {
200
- if /* We only need this section when/if we're actually serving. */($serving)
201
- c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */("file", $req["file_download"], "ccap", $req_ccap, $_SERVER["REQUEST_URI"]).exit();
202
-
203
- else // Else return false.
204
- return false;
205
- }
206
-
207
- else if /* In either case, the following routines apply. */($serving || $creating)
208
- {
209
- $user_previous_file_downloads = /* Downloads the User has already; in current period/cycle. */ 0;
210
- $user_already_downloaded_this_file = $user_already_downloaded_a_streaming_variation_of_this_file = false;
211
-
212
- $user_file_download_access_log = (is_array($user_file_download_access_log = get_user_option("s2member_file_download_access_log", $user_id))) ? $user_file_download_access_log : array();
213
- $user_file_download_access_arc = (is_array($user_file_download_access_arc = get_user_option("s2member_file_download_access_arc", $user_id))) ? $user_file_download_access_arc : array();
214
-
215
- $streaming_file_extns = c_ws_plugin__s2member_utils_strings::preg_quote_deep($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["streaming_file_extns"], "/");
216
- $streaming_variations = /* Only count one streaming media file variation. */ "/\.(".implode("|", $streaming_file_extns).")#x2F;i";
217
-
218
- foreach($user_file_download_access_log as $user_file_download_access_log_entry_key => $user_file_download_access_log_entry)
219
- {
220
- if( /* Weed out corrupt/empty log entries. */isset($user_file_download_access_log_entry["date"], $user_file_download_access_log_entry["file"]))
221
- {
222
- if(strtotime($user_file_download_access_log_entry["date"]) < strtotime("-".$user_file_downloads["allowed_days"]." days"))
223
- {
224
- unset /* Remove it from the `log`. */($user_file_download_access_log[$user_file_download_access_log_entry_key]);
225
- $user_file_download_access_arc[] = /* Move `log` entry to the `archive` now. */ $user_file_download_access_log_entry;
226
- }
227
- else if(strtotime($user_file_download_access_log_entry["date"]) >= strtotime("-".$user_file_downloads["allowed_days"]." days"))
228
- {
229
- $user_previous_file_downloads++; // Previous files always count against this User/Member.
230
-
231
- $_user_file_download_access_log_entry = &$user_file_download_access_log[$user_file_download_access_log_entry_key];
232
- $_user_already_downloaded_this_file = $_user_already_downloaded_a_streaming_variation_of_this_file = false;
233
-
234
- if /* Already downloaded this file? If yes, mark this flag as true. */($user_file_download_access_log_entry["file"] === $req["file_download"])
235
- $user_already_downloaded_this_file = $_user_already_downloaded_this_file = /* Already downloaded this file? If yes, mark as true. */ true;
236
-
237
- else if(preg_replace($streaming_variations, "", $user_file_download_access_log_entry["file"]) === preg_replace($streaming_variations, "", $req["file_download"]))
238
- $user_already_downloaded_this_file = $_user_already_downloaded_this_file = $user_already_downloaded_a_streaming_variation_of_this_file = $_user_already_downloaded_a_streaming_variation_of_this_file = true;
239
-
240
- if( /* Updating counter? */$updating_user_counter && ($_user_already_downloaded_this_file || $_user_already_downloaded_a_streaming_variation_of_this_file))
241
- {
242
- $_user_file_download_access_log_entry /* First, we update the last download time for this file. */["ltime"] = time();
243
-
244
- if( /* Backward compatibility here. Is this even set? */!empty($user_file_download_access_log_entry["counter"]))
245
- $_user_file_download_access_log_entry["counter"] = (int)$user_file_download_access_log_entry["counter"] + 1;
246
- else // Backward compatibility here. Default value to `1`, if this is NOT even set yet.
247
- $_user_file_download_access_log_entry["counter"] = 1 + 1;
248
- }
249
- }
250
- }
251
- else // Weed out empty log entries. Some older versions of s2Member may have corrupt/empty log entries.
252
- unset /* Remove. */($user_file_download_access_log[$user_file_download_access_log_entry_key]);
253
- }
254
- if( /* Updating counter? */$updating_user_counter && /* Do we need a new log entry for this file? */ !$user_already_downloaded_this_file && !$user_already_downloaded_a_streaming_variation_of_this_file)
255
- $user_file_download_access_log[] = array("date" => date("Y-m-d"), "time" => time(), "ltime" => time(), "file" => $req["file_download"], "counter" => 1);
256
-
257
- if($user_previous_file_downloads >= $user_file_downloads["allowed"] && !$user_already_downloaded_this_file && !$user_already_downloaded_a_streaming_variation_of_this_file && !$user->has_cap("administrator"))
258
- {
259
- if /* We only need this section when/if we're actually serving. */($serving)
260
- wp_redirect(add_query_arg(urlencode_deep(array("_s2member_seeking" => array("type" => "file", "file" => $req["file_download"], "_uri" => base64_encode($_SERVER["REQUEST_URI"])), "s2member_seeking" => "file-".$req["file_download"])), get_page_link($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"])), apply_filters("ws_plugin__s2member_content_redirect_status", 301, get_defined_vars())).exit();
261
-
262
- else // Else return false.
263
- return false;
264
- }
265
- else if /* Save/update counter? By default, we do NOT update the counter when a URL is simply being created for access. */($updating_user_counter)
266
- update_user_option($user_id, "s2member_file_download_access_log", c_ws_plugin__s2member_utils_arrays::array_unique($user_file_download_access_log)).update_user_option($user_id, "s2member_file_download_access_arc", c_ws_plugin__s2member_utils_arrays::array_unique($user_file_download_access_arc));
267
- }
268
- }
269
- }
270
- else // Otherwise, we're either NOT ``$checking_user``; or permission was granted with a valid File Download Key.
271
{
272
- if(!$using_amazon_storage && !file_exists($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"]."/".$req["file_download"]))
273
- {
274
- if /* We only need this section when/if we're actually serving. */($serving)
275
- {
276
- status_header(404);
277
- header("Content-Type: text/html; charset=UTF-8");
278
- while (@ob_end_clean ()); // Clean any existing output buffers.
279
- exit(_x('<strong>404: Sorry, file not found.</strong> Please contact Support for assistance.', "s2member-front", "s2member"));
280
- }
281
- else // Else return false.
282
- return false;
283
- }
284
}
285
-
286
- if /* In either case, the following routines apply. */($serving || $creating)
287
{
288
- $basename = basename($req["file_download"]);
289
- $mimetypes = parse_ini_file(dirname(dirname(dirname(__FILE__)))."/includes/mime-types.ini");
290
- $extension = strtolower(substr($req["file_download"], strrpos($req["file_download"], ".") + 1));
291
292
- $key = ($req["file_download_key"] && is_string($req["file_download_key"])) ? $req["file_download_key"] : false;
293
294
- $stream = (isset($req["file_stream"])) ? filter_var($req["file_stream"], FILTER_VALIDATE_BOOLEAN) : ((in_array($extension, preg_split("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_stream_extensions"]))) ? true : false);
295
- $inline = (!$stream && isset($req["file_inline"])) ? filter_var($req["file_inline"], FILTER_VALIDATE_BOOLEAN) : (($stream || in_array($extension, preg_split("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_inline_extensions"]))) ? true : false);
296
- $ssl = (isset($req["file_ssl"])) ? filter_var($req["file_ssl"], FILTER_VALIDATE_BOOLEAN) : ((is_ssl()) ? true : false);
297
- $storage = ($req["file_storage"] && is_string($req["file_storage"])) ? strtolower($req["file_storage"]) : false;
298
- $remote = (isset($req["file_remote"])) ? filter_var($req["file_remote"], FILTER_VALIDATE_BOOLEAN) : false;
299
300
- $_basename_dir_app_data = c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"]);
301
- $rewrite_base_guess = (is_dir(dirname($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir"])."/".$_basename_dir_app_data)) ? dirname($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"])."/".$_basename_dir_app_data : content_url("/".$_basename_dir_app_data);
302
- $rewrite_base = ($req["file_rewrite_base"] && is_string($req["file_rewrite_base"])) ? $req["file_rewrite_base"] : false;
303
- $rewrite = $rewriting = (!$rewrite_base && isset($req["file_rewrite"])) ? filter_var($req["file_rewrite"], FILTER_VALIDATE_BOOLEAN) : (($rewrite_base) ? true : false);
304
- unset /* A little housekeeping here. */($_basename_dir_app_data);
305
306
- $skip_confirmation = (isset($req["skip_confirmation"])) ? filter_var($req["skip_confirmation"], FILTER_VALIDATE_BOOLEAN) : false;
307
- $url_to_storage_source = (isset($req["url_to_storage_source"])) ? filter_var($req["url_to_storage_source"], FILTER_VALIDATE_BOOLEAN) : false;
308
-
309
- $pathinfo = (!$using_amazon_storage) ? pathinfo(($file = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"]."/".$req["file_download"])) : array();
310
- $mimetype = ($mimetypes[$extension]) ? $mimetypes[$extension] : "application/octet-stream";
311
- $disposition = (($inline) ? "inline" : "attachment")."; filename=\"".c_ws_plugin__s2member_utils_strings::esc_dq($basename)."\"; filename*=UTF-8''".rawurlencode($basename);
312
- $length = (!$using_amazon_storage && $file) ? filesize($file) : -1;
313
-
314
- foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$__v;
315
- do_action("ws_plugin__s2member_during_file_download_access", get_defined_vars());
316
- unset($__refs, $__v);
317
-
318
- if($using_amazon_storage && $using_amazon_cf_storage && ($serving || ($creating && $url_to_storage_source)))
319
- {
320
- if /* We only need this section when/if we're actually serving. */($serving)
321
- wp_redirect(c_ws_plugin__s2member_files_in::amazon_cf_url($req["file_download"], $stream, $inline, $ssl, $basename, $mimetype)).exit();
322
323
- else // Else return File Download URL.
324
- return apply_filters("ws_plugin__s2member_file_download_access_url", c_ws_plugin__s2member_files_in::amazon_cf_url($req["file_download"], $stream, $inline, $ssl, $basename, $mimetype), get_defined_vars());
325
- }
326
327
- else if($using_amazon_storage && $using_amazon_s3_storage && ($serving || ($creating && $url_to_storage_source)))
328
- {
329
- if /* We only need this section when/if we're actually serving. */($serving)
330
- wp_redirect(c_ws_plugin__s2member_files_in::amazon_s3_url($req["file_download"], $stream, $inline, $ssl, $basename, $mimetype)).exit();
331
332
- else // Else return File Download URL.
333
- return apply_filters("ws_plugin__s2member_file_download_access_url", c_ws_plugin__s2member_files_in::amazon_s3_url($req["file_download"], $stream, $inline, $ssl, $basename, $mimetype), get_defined_vars());
334
- }
335
336
- else if /* Creating a rewrite URL, pointing to local storage. */($creating && $rewriting)
337
- { // Note: we don't URL encode unreserved chars. Improves media player compatibility.
338
- $_url_e_key = ($key) ? c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($key)) : "";
339
- $_url_e_storage = ($storage) ? c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($storage)) : "";
340
- $_url_e_file = c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($req["file_download"]));
341
- $_url_e_file = str_ireplace("%2F", "/", $_url_e_file);
342
-
343
- $url = ($rewrite_base) ? rtrim($rewrite_base, "/") : rtrim($rewrite_base_guess, "/");
344
- $url .= (isset($req["file_download_key"])) ? (($key && $_url_e_key) ? "/s2member-file-download-key-".$_url_e_key : "") : "";
345
- $url .= (isset($req["file_stream"])) ? (($stream) ? "/s2member-file-stream" : "/s2member-file-stream-no") : "";
346
- $url .= (isset($req["file_inline"])) ? (($inline) ? "/s2member-file-inline" : "/s2member-file-inline-no") : "";
347
- $url .= (isset($req["file_storage"])) ? (($storage && $_url_e_storage) ? "/s2member-file-storage-".$_url_e_storage : "") : "";
348
- $url .= (isset($req["file_remote"])) ? (($remote) ? "/s2member-file-remote" : "/s2member-file-remote-no") : "";
349
- $url .= (isset($req["skip_confirmation"])) ? (($skip_confirmation) ? "/s2member-skip-confirmation" : "/s2member-skip-confirmation-no") : "";
350
-
351
- $url = /* File Download Access URL via `mod_rewrite` functionality. */ $url."/".$_url_e_file;
352
- $url = ($ssl) ? preg_replace("/^https?/", "https", $url) : preg_replace("/^https?/", "http", $url);
353
-
354
- return apply_filters("ws_plugin__s2member_file_download_access_url", $url, get_defined_vars());
355
- }
356
357
- else if /* Else we're creating a URL w/ a query-string; w/ local storage. */($creating)
358
- { // Note: we don't URL encode unreserved chars. Improves media player compatibility.
359
- $_url_e_key = ($key) ? c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($key)) : "";
360
- $_url_e_storage = ($storage) ? c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($storage)) : "";
361
- $_url_e_file = c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($req["file_download"]));
362
- $_url_e_file = str_ireplace("%2F", "/", $_url_e_file);
363
364
- $url = (isset($req["file_download_key"])) ? (($key && $_url_e_key) ? "&s2member_file_download_key=".$_url_e_key : "") : "";
365
- $url .= (isset($req["file_stream"])) ? (($stream) ? "&s2member_file_stream=yes" : "&s2member_file_stream=no") : "";
366
- $url .= (isset($req["file_inline"])) ? (($inline) ? "&s2member_file_inline=yes" : "&s2member_file_inline=no") : "";
367
- $url .= (isset($req["file_storage"])) ? (($storage && $_url_e_storage) ? "&s2member_file_storage=".$_url_e_storage : "") : "";
368
- $url .= (isset($req["file_remote"])) ? (($remote) ? "&s2member_file_remote=yes" : "&s2member_file_remote=no") : "";
369
- $url .= (isset($req["skip_confirmation"])) ? (($skip_confirmation) ? "&s2member_skip_confirmation=yes" : "&s2member_skip_confirmation=no") : "";
370
371
- $url = site_url("/?".ltrim($url."&s2member_file_download=/".$_url_e_file, "&"));
372
- $url = ($ssl) ? preg_replace("/^https?/", "https", $url) : preg_replace("/^https?/", "http", $url);
373
374
- return apply_filters("ws_plugin__s2member_file_download_access_url", $url, get_defined_vars());
375
- }
376
377
- else if /* Else, ``if ($serving)``, use local storage. */($serving)
378
- {
379
- @set_time_limit(0);
380
-
381
- @ini_set("zlib.output_compression", 0);
382
- if(function_exists("apache_setenv"))
383
- @apache_setenv("no-gzip", "1");
384
-
385
- $content_encoding_header = "Content-Encoding:"; // Default value; standards compliant.
386
- if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_content_encodong_none"])
387
- $content_encoding_header = "Content-Encoding: none";
388
-
389
- while /* Cleans existing output buffers. */(@ob_end_clean());
390
-
391
- if /* Requesting a specific byte range? */($range)
392
- {
393
- if /* Invalid range? */(strpos($range, "=") === FALSE)
394
- {
395
- status_header(416);
396
- nocache_headers();
397
- header($content_encoding_header);
398
- header("Accept-Ranges: bytes");
399
- header("Content-Type: ".$mimetype);
400
- header("Content-Length: ".$length);
401
- header("Content-Disposition: ".$disposition);
402
- exit /* Stop here (invalid). */();
403
- }
404
- list($range_type, $byte_range) = preg_split("/\s*\=\s*/", $range, 2);
405
-
406
- $range_type = strtolower(trim($range_type));
407
- $byte_range = trim($byte_range);
408
-
409
- if /* Invalid range type? */($range_type !== "bytes")
410
- {
411
- status_header(416);
412
- nocache_headers();
413
- header($content_encoding_header);
414
- header("Accept-Ranges: bytes");
415
- header("Content-Type: ".$mimetype);
416
- header("Content-Length: ".$length);
417
- header("Content-Disposition: ".$disposition);
418
- exit /* Stop here (invalid). */();
419
- }
420
- $byte_ranges = preg_split("/\s*,\s*/", $byte_range);
421
-
422
- if /* Invalid byte range? */(strpos($byte_ranges[0], "-") === FALSE)
423
- {
424
- status_header(416);
425
- nocache_headers();
426
- header($content_encoding_header);
427
- header("Accept-Ranges: bytes");
428
- header("Content-Type: ".$mimetype);
429
- header("Content-Length: ".$length);
430
- header("Content-Disposition: ".$disposition);
431
- exit /* Stop here (invalid). */();
432
- }
433
-
434
- // Only dealing with the first byte range. Others are simply ignored here.
435
- list($byte_range_start, $byte_range_stops) = preg_split("/\s*\-\s*/", $byte_ranges[0], 2);
436
-
437
- $byte_range_start = trim($byte_range_start);
438
- $byte_range_stops = trim($byte_range_stops);
439
-
440
- $byte_range_start = ($byte_range_start === "") ? NULL : (integer)$byte_range_start;
441
- $byte_range_stops = ($byte_range_stops === "") ? NULL : (integer)$byte_range_stops;
442
-
443
- if(!isset($byte_range_start) && $byte_range_stops > 0 && $byte_range_stops <= $length)
444
- {
445
- $byte_range_start = $length - $byte_range_stops;
446
- $byte_range_stops = /* The last X number of bytes. */ $length - 1;
447
- }
448
- else if(!isset($byte_range_stops) && $byte_range_start >= 0 && $byte_range_start < $length - 1)
449
- {
450
- $byte_range_stops = /* To the end of the file in this case. */ $length - 1;
451
- }
452
- else if(isset($byte_range_start, $byte_range_stops) && $byte_range_start >= 0 && $byte_range_start < $length - 1 && $byte_range_stops > $byte_range_start && $byte_range_stops <= $length - 1) {
453
- // Nothing to do in this case, starts/stops already defined properly.
454
- }
455
- else // We have an invalid byte range.
456
- {
457
- status_header(416);
458
- nocache_headers();
459
- header($content_encoding_header);
460
- header("Accept-Ranges: bytes");
461
- header("Content-Type: ".$mimetype);
462
- header("Content-Length: ".$length);
463
- header("Content-Disposition: ".$disposition);
464
- exit /* Stop here (invalid). */();
465
- }
466
- // Range.
467
- status_header(206);
468
- nocache_headers();
469
- header($content_encoding_header);
470
- header("Accept-Ranges: bytes");
471
- header("Content-Type: ".$mimetype);
472
- header("Content-Range: bytes ".$byte_range_start."-".$byte_range_stops."/".$length);
473
- $byte_range_size = $byte_range_stops - $byte_range_start + 1;
474
- header("Content-Length: ".$byte_range_size);
475
- header("Content-Disposition: ".$disposition);
476
- }
477
- else // A normal request (NOT a specific byte range).
478
- {
479
- status_header(200);
480
- nocache_headers();
481
- header($content_encoding_header);
482
- header("Accept-Ranges: bytes");
483
- header("Content-Type: ".$mimetype);
484
- header("Content-Length: ".$length);
485
- header("Content-Disposition: ".$disposition);
486
- }
487
- if(is_resource($resource = fopen($file, "rb")))
488
- {
489
- if($range)
490
- {
491
- $_bytes_to_read = $byte_range_size;
492
- fseek($resource, $byte_range_start);
493
- }
494
- else // Entire file.
495
- $_bytes_to_read = $length;
496
-
497
- $chunk_size = apply_filters("ws_plugin__s2member_file_downloads_chunk_size", 2097152, get_defined_vars());
498
-
499
- while /* We have bytes to read here. */($_bytes_to_read)
500
- {
501
- $_bytes_to_read -= ($_reading = ($_bytes_to_read > $chunk_size) ? $chunk_size : $_bytes_to_read);
502
- echo /* Serve file in chunks (default chunk size is 2MB). */ fread($resource, $_reading);
503
- flush /* Flush each chunk to the browser as it is served (avoids high memory consumption). */();
504
- }
505
- fclose /* Close file resource handle. */($resource);
506
- unset /* Housekeeping. */($_bytes_to_read, $_reading);
507
- }
508
- exit /* Stop execution now (the file has been served). */();
509
- }
510
- }
511
}
512
-
513
- else if /* We only need this section when/if we're actually serving. */($serving && $req["file_download"])
514
{
515
- status_header(503);
516
- header("Content-Type: text/html; charset=UTF-8");
517
- while (@ob_end_clean ()); // Clean any existing output buffers.
518
- exit(_x('<strong>503: Access denied.</strong> Invalid File Download specs.', "s2member-front", "s2member"));
519
}
520
- else if /* We only need this section when/if we're creating a URL. */($creating)
521
- return false;
522
523
- do_action("ws_plugin__s2member_after_file_download_access", get_defined_vars());
524
525
- return ($creating) ? /* If creating, false. */ false : null;
526
}
527
- /**
528
- * Generates a File Download URL for access to a file protected by s2Member.
529
- *
530
- * @package s2Member\Files
531
- * @since 110926
532
- *
533
- * @param array $config Required. This is an array of configuration options associated with permissions being checked against the current User/Member; and also the actual URL generated by this routine.
534
- * Possible ``$config`` array elements: `file_download` *(required)*, `file_download_key`, `file_stream`, `file_inline`, `file_storage`, `file_remote`, `file_ssl`, `file_rewrite`, `file_rewrite_base`, `skip_confirmation`, `url_to_storage_source`, `count_against_user`, `check_user`.
535
- * @param bool $get_streamer_array Optional. Defaults to `false`. If `true`, this function will return an array with the following elements: `streamer`, `file`, `url`. For further details, please review this section in your Dashboard: `s2Member -› Download Options -› JW Player & RTMP Protocol Examples`.
536
- * @return string A File Download URL string on success; or an array on success, with elements `streamer`, `file`, `url` when/if ``$get_streamer_array`` is true; else false on any type of failure.
537
- *
538
- * @see s2Member\API_Functions\s2member_file_download_url()
539
- */
540
- public static function create_file_download_url($config = FALSE, $get_streamer_array = FALSE)
541
- {
542
- foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$__v;
543
- do_action("ws_plugin__s2member_before_create_file_download_url", get_defined_vars());
544
- unset($__refs, $__v);
545
-
546
- $config = (is_array($config)) ? $config : /* This absolutely MUST be an array. */ array();
547
548
- $config["file_download"] = (isset($config["file_download"]) && is_string($config["file_download"])) ? trim($config["file_download"], "/") : @$config["file_download"];
549
- $config["file_download_key"] = (isset($config["file_download"]) && is_string($config["file_download"]) && !empty($config["file_download_key"])) ? c_ws_plugin__s2member_files::file_download_key($config["file_download"], ((in_array($config["file_download_key"], array("ip-forever", "universal", "cache-compatible"))) ? $config["file_download_key"] : false)) : @$config["file_download_key"];
550
551
- $config["url_to_storage_source"] = /* Force a streaming URL here via ``$get_streamer_array``? */ ($get_streamer_array) ? true : @$config["url_to_storage_source"];
552
- $config["file_stream"] = /* Force a streaming URL here via ``$get_streamer_array``? */ ($get_streamer_array) ? true : @$config["file_stream"];
553
554
- if(($_url = c_ws_plugin__s2member_files_in::check_file_download_access /* Successfully created a URL to the file? */(($create_file_download_url = $config))))
555
- {
556
- foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$__v;
557
- do_action("ws_plugin__s2member_during_create_file_download_url", get_defined_vars());
558
- unset($__refs, $__v);
559
-
560
- $extension = strtolower(substr($config["file_download"], strrpos($config["file_download"], ".") + 1));
561
- $streaming = (isset($config["file_stream"])) ? filter_var($config["file_stream"], FILTER_VALIDATE_BOOLEAN) : ((in_array($extension, preg_split("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_stream_extensions"]))) ? true : false);
562
- $ssl = (isset($config["file_ssl"])) ? filter_var($config["file_ssl"], FILTER_VALIDATE_BOOLEAN) : ((is_ssl()) ? true : false);
563
564
- if($get_streamer_array && $streaming && ($cfx = "/cfx/st") && ($cfx_pos = strpos($_url, $cfx)) !== false && ($streamer = substr($_url, 0, $cfx_pos + strlen($cfx))) && ($url = c_ws_plugin__s2member_files_in::check_file_download_access(array_merge($config, array("file_stream" => false, "check_user" => false, "count_against_user" => false)))))
565
- $return = array("streamer" => $streamer, "prefix" => $extension.":", "file" => preg_replace("/^".preg_quote($streamer, "/")."\//", "", $_url), "url" => preg_replace("/^.+?\:/", (($ssl) ? "https:" : "http:"), $url));
566
567
- else if($get_streamer_array && $streaming && is_array($ups = c_ws_plugin__s2member_utils_urls::parse_url($_url)) && isset($ups["scheme"], $ups["host"]) && ($streamer = $ups["scheme"]."://".$ups["host"].((!empty($ups["port"])) ? ":".$ups["port"] : "")) && ($url = c_ws_plugin__s2member_files_in::check_file_download_access(array_merge($config, array("file_stream" => false, "check_user" => false, "count_against_user" => false)))))
568
- $return = array("streamer" => $streamer, "prefix" => $extension.":", "file" => preg_replace("/^".preg_quote($streamer, "/")."\//", "", $_url), "url" => preg_replace("/^.+?\:/", (($ssl) ? "https:" : "http:"), $url));
569
570
- else if /* If streamer, we MUST return false here; unable to acquire streamer/file. */($get_streamer_array)
571
- $return = /* We MUST return false here, unable to acquire streamer/file. */ false;
572
573
- else // Else return URL string ( ``$get_streamer_array`` is false ).
574
- $return = /* Else return URL string. */ $_url;
575
- }
576
577
- return apply_filters("ws_plugin__s2member_create_file_download_url", ((isset($return)) ? $return : false), get_defined_vars());
578
- }
579
- /**
580
- * Checks Header Authorization for Remote File Downloads.
581
- *
582
- * @package s2Member\Files
583
- * @since 110926
584
- *
585
- * @attaches-to ``add_filter("ws_plugin__s2member_check_file_download_access_user");``
586
- *
587
- * @param object $user Expects a WP_User object passed in by the Filter.
588
- * @return obj A `WP_User` object, possibly obtained through Header Authorization.
589
- */
590
- public static function check_file_remote_authorization($user = FALSE)
591
- {
592
- foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$__v;
593
- do_action("ws_plugin__s2member_before_check_file_remote_authorization", get_defined_vars());
594
- unset($__refs, $__v);
595
596
- $_g = c_ws_plugin__s2member_utils_strings::trim_deep(stripslashes_deep(((!empty($_GET)) ? $_GET : array())));
597
598
- if(!is_object($user) && isset($_g["s2member_file_remote"]) && filter_var($_g["s2member_file_remote"], FILTER_VALIDATE_BOOLEAN))
599
- {
600
- do_action("ws_plugin__s2member_during_check_file_remote_authorization_before", get_defined_vars());
601
602
- if((empty($_SERVER["PHP_AUTH_USER"]) || $_SERVER["PHP_AUTH_USER"] === "NOUSER") && !empty($_SERVER["HTTP_AUTHORIZATION"]))
603
- {
604
- $auth = trim(preg_replace("/^.+?\s+/", "", $_SERVER["HTTP_AUTHORIZATION"]));
605
- $auth = explode(":", base64_decode($auth), 2);
606
607
- if(!empty($auth[0])) $_SERVER["PHP_AUTH_USER"] = $auth[0];
608
- if(!empty($auth[1])) $_SERVER["PHP_AUTH_PW"] = $auth[1];
609
- }
610
- if(empty($_SERVER["PHP_AUTH_USER"]) || empty($_SERVER["PHP_AUTH_PW"]) || !user_pass_ok($_SERVER["PHP_AUTH_USER"], $_SERVER["PHP_AUTH_PW"]))
611
- {
612
- header('WWW-Authenticate: Basic realm="'.c_ws_plugin__s2member_utils_strings::esc_dq(strip_tags(_x("Members Only", "s2member-front", "s2member"))).'"');
613
614
- status_header /* Send an unauthorized 401 status header now. */(401);
615
- header /* Content-Type with UTF-8. */("Content-Type: text/html; charset=UTF-8");
616
- while (@ob_end_clean ()); // Clean any existing output buffers.
617
618
- exit(_x('<strong>401:</strong> Sorry, access denied.', "s2member-front", "s2member"));
619
- }
620
- else if(is_object($_user = new WP_User($_SERVER["PHP_AUTH_USER"])) && !empty($_user->ID))
621
- $user = /* Now assign ``$user``. */ $_user;
622
623
- do_action("ws_plugin__s2member_during_check_file_remote_authorization_after", get_defined_vars());
624
- }
625
- return apply_filters("ws_plugin__s2member_check_file_remote_authorization", $user, get_defined_vars());
626
- }
627
- /**
628
- * Checks a File Download Key for validity.
629
- *
630
- * @package s2Member\Files
631
- * @since 110926
632
- *
633
- * @param string $file Input File Download to validate.
634
- * @param string $key Input File Download Key to validate.
635
- * @return bool True if valid, else false.
636
- */
637
- public static function check_file_download_key($file = FALSE, $key = FALSE)
638
{
639
- foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$__v;
640
- do_action("_ws_plugin__s2member_before_check_file_download_key", get_defined_vars());
641
- unset($__refs, $__v);
642
-
643
- if($file && is_string($file) && ($file = trim($file, "/")) && $key && is_string($key))
644
{
645
- if($key === c_ws_plugin__s2member_files::file_download_key($file) || $key === c_ws_plugin__s2member_files::file_download_key("/".$file))
646
- $valid = /* File Download Key is valid. */ true;
647
- else if($key === c_ws_plugin__s2member_files::file_download_key($file, "ip-forever") || $key === c_ws_plugin__s2member_files::file_download_key("/".$file, "ip-forever"))
648
- $valid = /* File Download Key is valid. */ true;
649
- else if($key === c_ws_plugin__s2member_files::file_download_key($file, "universal") || $key === c_ws_plugin__s2member_files::file_download_key("/".$file, "universal"))
650
- $valid = /* File Download Key is valid. */ true;
651
- }
652
- return apply_filters("ws_plugin__s2member_check_file_download_key", ((isset($valid) && $valid) ? true : false), get_defined_vars());
653
- }
654
- /**
655
- * Creates an Amazon S3 HMAC-SHA1 signature.
656
- *
657
- * @package s2Member\Files
658
- * @since 110524RC
659
- *
660
- * @param string $string Input string/data, to be signed by this routine.
661
- * @return string An HMAC-SHA1 signature for Amazon S3.
662
- */
663
- public static function amazon_s3_sign($string = FALSE)
664
- {
665
- $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
666
667
- return c_ws_plugin__s2member_utils_strings::hmac_sha1_sign((string)$string, $s3c["secret_key"]);
668
- }
669
- /**
670
- * Creates an Amazon S3 HMAC-SHA1 signature URL.
671
- *
672
- * @package s2Member\Files
673
- * @since 110926
674
- *
675
- * @param string $file Input file path, to be signed by this routine.
676
- * @param bool $stream Is this resource file to be served as streaming media?
677
- * @param bool $inline Is this resource file to be served inline, or no?
678
- * @param bool $ssl Is this resource file to be served via SSL, or no?
679
- * @param string $basename The absolute basename of the resource file.
680
- * @param string $mimetype The MIME content-type of the resource file.
681
- * @return string An HMAC-SHA1 signature URL for Amazon S3.
682
- */
683
- public static function amazon_s3_url($file = FALSE, $stream = FALSE, $inline = FALSE, $ssl = FALSE, $basename = FALSE, $mimetype = FALSE)
684
- {
685
- $file = /* Trim / force string. */ trim((string)$file, "/");
686
- $url_e_file = c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($file));
687
- $url_e_file = str_ireplace("%2F", "/", $url_e_file);
688
689
- foreach($GLOBALS["WS_PLUGIN__"]["s2member"]["o"] as $option => $option_value)
690
- if(preg_match("/^amazon_s3_files_/", $option) && ($option = preg_replace("/^amazon_s3_files_/", "", $option)))
691
- $s3c[$option] = $option_value;
692
-
693
- $s3c["expires"] = strtotime("+".apply_filters("ws_plugin__s2member_amazon_s3_file_expires_time", "24 hours", get_defined_vars()));
694
695
- $s3_file = add_query_arg(c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode_deep(array("response-cache-control" => ($s3_cache_control = "no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0"), "response-content-disposition" => ($s3_content_disposition = (((bool)$inline) ? "inline" : "attachment").'; filename="'.(string)$basename.'"'), "response-content-type" => ($s3_content_type = (string)$mimetype), "response-expires" => ($s3_expires = gmdate("D, d M Y H:i:s", strtotime("-1 week"))." GMT")))), "/".$url_e_file);
696
- $s3_raw_file = add_query_arg(array("response-cache-control" => $s3_cache_control, "response-content-disposition" => $s3_content_disposition, "response-content-type" => $s3_content_type, "response-expires" => $s3_expires), "/".$url_e_file);
697
- $s3_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_s3_sign("GET\n\n\n".$s3c["expires"]."\n"."/".$s3c["bucket"].$s3_raw_file));
698
699
- $s3_url = ((strtolower($s3c["bucket"]) !== $s3c["bucket"])) ? "http".(($ssl) ? "s" : "")."://s3.amazonaws.com/".$s3c["bucket"].$s3_file : "http".(($ssl) ? "s" : "")."://".$s3c["bucket"].".s3.amazonaws.com".$s3_file;
700
701
- return add_query_arg(c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep (urlencode_deep(array("AWSAccessKeyId" => $s3c["access_key"], "Expires" => $s3c["expires"], "Signature" => $s3_signature))), $s3_url);
702
}
703
- /**
704
- * Auto-configures an Amazon S3 Bucket's ACLs.
705
- *
706
- * @package s2Member\Files
707
- * @since 110926
708
- *
709
- * @return array Array containing a true `success` element on success, else a failure array.
710
- * Failure array will contain a failure `code`, and a failure `message`.
711
- */
712
- public static function amazon_s3_auto_configure_acls()
713
- {
714
- foreach($GLOBALS["WS_PLUGIN__"]["s2member"]["o"] as $option => $option_value)
715
- if(preg_match("/^amazon_s3_files_/", $option) && ($option = preg_replace("/^amazon_s3_files_/", "", $option)))
716
- $s3c[$option] = $option_value;
717
-
718
- $cfc["distros_s3_access_id"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distros_s3_access_id"];
719
720
- if /* Must have Amazon S3 Bucket/Keys. */($s3c["bucket"] && $s3c["access_key"] && $s3c["secret_key"])
721
- {
722
- $s3_date = gmdate("D, d M Y H:i:s")." GMT";
723
- $s3_location = ((strtolower($s3c["bucket"]) !== $s3c["bucket"])) ? "/".$s3c["bucket"]."/?acl" : "/?acl";
724
- $s3_domain = ((strtolower($s3c["bucket"]) !== $s3c["bucket"])) ? "s3.amazonaws.com" : $s3c["bucket"].".s3.amazonaws.com";
725
- $s3_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_s3_sign("GET\n\n\n".$s3_date."\n/".$s3c["bucket"]."/?acl"));
726
- $s3_args = array("method" => "GET", "redirection" => 5, "headers" => array("Host" => $s3_domain, "Date" => $s3_date, "Authorization" => "AWS ".$s3c["access_key"].":".$s3_signature));
727
728
- if(($s3_response = c_ws_plugin__s2member_utils_urls::remote("https://".$s3_domain.$s3_location, false, array_merge($s3_args, array("timeout" => 20)), "array")) && $s3_response["code"] === 200)
729
- {
730
- if(preg_match("/\<Owner\>(.+?)\<\/Owner\>/is", $s3_response["body"], $s3_owner_tag) && preg_match("/\<ID\>(.+?)\<\/ID\>/is", $s3_owner_tag[1], $s3_owner_id_tag) && (preg_match("/\<DisplayName\>(.*?)\<\/DisplayName\>/is", $s3_owner_tag[1], $s3_owner_display_name_tag) || ($s3_owner_display_name_tag = array("-", "Owner"))))
731
- {
732
- $s3_owner = array("access_id" => trim($s3_owner_id_tag[1]), "display_name" => trim($s3_owner_display_name_tag[1]));
733
- $s3_acls_xml = '<AccessControlPolicy><Owner><ID>'.esc_html($s3_owner["access_id"]).'</ID><DisplayName>'.esc_html($s3_owner["display_name"]).'</DisplayName></Owner><AccessControlList><Grant><Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser"><ID>'.esc_html($s3_owner["access_id"]).'</ID><DisplayName>'.esc_html($s3_owner["display_name"]).'</DisplayName></Grantee><Permission>FULL_CONTROL</Permission></Grant>'.(($cfc["distros_s3_access_id"]) ? '<Grant><Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser"><ID>'.esc_html($cfc["distros_s3_access_id"]).'</ID><DisplayName>s2Member/CloudFront</DisplayName></Grantee><Permission>READ</Permission></Grant>' : '').'</AccessControlList></AccessControlPolicy>';
734
- $s3_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_s3_sign("PUT\n\napplication/xml\n".$s3_date."\n/".$s3c["bucket"]."/?acl"));
735
- $s3_args = array("method" => "PUT", "redirection" => 5, "body" => $s3_acls_xml, "headers" => array("Host" => $s3_domain, "Content-Type" => "application/xml", "Date" => $s3_date, "Authorization" => "AWS ".$s3c["access_key"].":".$s3_signature));
736
737
- if(($s3_response = c_ws_plugin__s2member_utils_urls::remote("https://".$s3_domain.$s3_location, false, array_merge($s3_args, array("timeout" => 20)), "array")) && $s3_response["code"] === 200)
738
- {
739
- $s3_location = ((strtolower($s3c["bucket"]) !== $s3c["bucket"])) ? "/".$s3c["bucket"]."/?policy" : "/?policy";
740
- ($s3_policy_id = md5(uniqid("s2Member/CloudFront:", true))).($s3_policy_sid = md5(uniqid("s2Member/CloudFront:", true)));
741
- $s3_policy_json = '{"Version":"2008-10-17","Id":"'.c_ws_plugin__s2member_utils_strings::esc_dq($s3_policy_id).'","Statement":[{"Sid":"'.c_ws_plugin__s2member_utils_strings::esc_dq($s3_policy_sid).'","Effect":"Allow","Principal":{"CanonicalUser":"'.c_ws_plugin__s2member_utils_strings::esc_dq($cfc["distros_s3_access_id"]).'"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::'.c_ws_plugin__s2member_utils_strings::esc_dq($s3c["bucket"]).'/*"}]}';
742
- $s3_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_s3_sign("PUT\n\napplication/json\n".$s3_date."\n/".$s3c["bucket"]."/?policy"));
743
- $s3_args = array("method" => "PUT", "redirection" => 5, "body" => $s3_policy_json, "headers" => array("Host" => $s3_domain, "Content-Type" => "application/json", "Date" => $s3_date, "Authorization" => "AWS ".$s3c["access_key"].":".$s3_signature));
744
745
- if(!$cfc["distros_s3_access_id"] || (($s3_response = c_ws_plugin__s2member_utils_urls::remote("https://".$s3_domain.$s3_location, false, array_merge($s3_args, array("timeout" => 20)), "array")) && ($s3_response["code"] === 200 || $s3_response["code"] === 204 /* Also OK. */)))
746
- {
747
- $s3_location = ((strtolower($s3c["bucket"]) !== $s3c["bucket"])) ? "/".$s3c["bucket"]."/crossdomain.xml" : "/crossdomain.xml";
748
- $s3_policy_xml = trim(c_ws_plugin__s2member_utilities::evl(file_get_contents(dirname(dirname(__FILE__))."/templates/cfg-files/s2-cross-xml.php")));
749
- $s3_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_s3_sign("PUT\n\ntext/xml\n".$s3_date."\nx-amz-acl:public-read\n/".$s3c["bucket"]."/crossdomain.xml"));
750
- $s3_args = array("method" => "PUT", "redirection" => 5, "body" => $s3_policy_xml, "headers" => array("Host" => $s3_domain, "Content-Type" => "text/xml", "Date" => $s3_date, "X-Amz-Acl" => "public-read", "Authorization" => "AWS ".$s3c["access_key"].":".$s3_signature));
751
752
- if(($s3_response = c_ws_plugin__s2member_utils_urls::remote("https://".$s3_domain.$s3_location, false, array_merge($s3_args, array("timeout" => 20)), "array")) && $s3_response["code"] === 200)
753
- return /* Successfully configured Amazon S3 Bucket ACLs and Policy. */ array("success" => true, "code" => null, "message" => null);
754
755
- else if(isset($s3_response["code"], $s3_response["message"]))
756
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon S3 API call. Feel free to exclude `%s` if you like. */
757
- return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon S3 Cross-Domain Policy. %s", "s2member-admin", "s2member"), $s3_response["message"]));
758
759
- else // Else, we use a default error code and message.
760
- return array("success" => false, "code" => -94, "message" => _x("Unable to update existing Amazon S3 Cross-Domain Policy. Connection failed.", "s2member-admin", "s2member"));
761
- }
762
- else if(isset($s3_response["code"], $s3_response["message"]))
763
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon S3 API call. Feel free to exclude `%s` if you like. */
764
- return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon S3 Bucket Policy. %s", "s2member-admin", "s2member"), $s3_response["message"]));
765
766
- else // Else, we use a default error code and message.
767
- return array("success" => false, "code" => -95, "message" => _x("Unable to update existing Amazon S3 Bucket Policy. Connection failed.", "s2member-admin", "s2member"));
768
- }
769
- else if(isset($s3_response["code"], $s3_response["message"]))
770
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon S3 API call. Feel free to exclude `%s` if you like. */
771
- return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon S3 Bucket ACLs. %s", "s2member-admin", "s2member"), $s3_response["message"]));
772
773
- else // Else, we use a default error code and message.
774
- return array("success" => false, "code" => -96, "message" => _x("Unable to update existing Amazon S3 Bucket ACLs. Connection failed.", "s2member-admin", "s2member"));
775
- }
776
- else // Else, we use a default error code and message.
777
- return array("success" => false, "code" => -97, "message" => _x("Unable to acquire/read existing Amazon S3 Bucket ACLs. Unexpected response.", "s2member-admin", "s2member"));
778
- }
779
- else if(isset($s3_response["code"], $s3_response["message"]))
780
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon S3 API call. Feel free to exclude `%s` if you like. */
781
- return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon S3 Bucket ACLs. %s", "s2member-admin", "s2member"), $s3_response["message"]));
782
783
- else // Else, we use a default error code and message.
784
- return array("success" => false, "code" => -98, "message" => _x("Unable to acquire existing Amazon S3 Bucket ACLs. Connection failed.", "s2member-admin", "s2member"));
785
- }
786
- else // Else, we use a default error code and message.
787
- return array("success" => false, "code" => -99, "message" => _x("Unable to auto-configure existing Amazon S3 Bucket ACLs. Incomplete Amazon S3 configuration options. Missing one of: Amazon S3 Bucket, Access Key, or Secret Key.", "s2member-admin", "s2member"));
788
- }
789
- /**
790
- * Creates an Amazon CloudFront HMAC-SHA1 signature.
791
- *
792
- * @package s2Member\Files
793
- * @since 110926
794
- *
795
- * @param string $string Input string/data, to be signed by this routine.
796
- * @return string An HMAC-SHA1 signature for Amazon CloudFront.
797
- */
798
- public static function amazon_cf_sign($string = FALSE)
799
- {
800
- $cfc["secret_key"] = $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
801
802
- return c_ws_plugin__s2member_utils_strings::hmac_sha1_sign((string)$string, ($cfc["secret_key"] = $s3c["secret_key"]));
803
- }
804
- /**
805
- * Creates an Amazon CloudFront RSA-SHA1 signature.
806
- *
807
- * @package s2Member\Files
808
- * @since 110926
809
- *
810
- * @param string $string Input string/data, to be signed by this routine.
811
- * @return str|bool An RSA-SHA1 signature for Amazon CloudFront, else false on failure.
812
- */
813
- public static function amazon_cf_rsa_sign($string = FALSE)
814
- {
815
- $cfc["private_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_private_key"];
816
817
- return c_ws_plugin__s2member_utils_strings::rsa_sha1_sign((string)$string, $cfc["private_key"]);
818
- }
819
- /**
820
- * Creates an Amazon CloudFront RSA-SHA1 signature URL.
821
- *
822
- * @package s2Member\Files
823
- * @since 110926
824
- *
825
- * @param string $file Input file path, to be signed by this routine.
826
- * @param bool $stream Is this resource file to be served as streaming media?
827
- * @param bool $inline Is this resource file to be served inline, or no?
828
- * @param bool $ssl Is this resource file to be served via SSL, or no?
829
- * @param string $basename The absolute basename of the resource file.
830
- * @param string $mimetype The MIME content-type of the resource file.
831
- * @return string An RSA-SHA1 signature URL for Amazon CloudFront.
832
- */
833
- public static function amazon_cf_url($file = FALSE, $stream = FALSE, $inline = FALSE, $ssl = FALSE, $basename = FALSE, $mimetype = FALSE)
834
- {
835
- $file = /* Trim & force string. */ trim((string)$file, "/");
836
- $url_e_file = c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($file));
837
- $url_e_file = str_ireplace("%2F", "/", $url_e_file);
838
839
- foreach($GLOBALS["WS_PLUGIN__"]["s2member"]["o"] as $option => $option_value)
840
- if(preg_match("/^amazon_cf_files_/", $option) && ($option = preg_replace("/^amazon_cf_files_/", "", $option)))
841
- $cfc[$option] = $option_value;
842
843
- $cfc["expires"] = strtotime("+".apply_filters("ws_plugin__s2member_amazon_cf_file_expires_time", "24 hours", get_defined_vars()));
844
845
- $cf_extn = /* Parses the file extension out so we can scan it in some special scenarios. */ strtolower(substr($file, strrpos($file, ".") + 1));
846
- $cf_ip_res = /* Do NOT restrict access to a particular IP during `localhost` development. The IP may NOT be the same one Amazon CloudFront sees. */ (c_ws_plugin__s2member_utils_conds::is_localhost()) ? false : true;
847
- $cf_stream_extn_resource_exclusions = array_unique((array)apply_filters("ws_plugin__s2member_amazon_cf_file_streaming_extension_resource_exclusions", array("mp3" /* MP3 files should NOT include an extension in their resource reference. */), get_defined_vars()));
848
- $cf_resource = ($stream) ? ((in_array($cf_extn, $cf_stream_extn_resource_exclusions)) ? substr($file, 0, strrpos($file, ".")) : $file) : "http".(($ssl) ? "s" : "")."://".(($cfc["distro_downloads_cname"]) ? $cfc["distro_downloads_cname"] : $cfc["distro_downloads_dname"])."/".$url_e_file;
849
- $cf_url = ($stream) ? "rtmp".(($ssl) ? "e" : "")."://".(($cfc["distro_streaming_cname"]) ? $cfc["distro_streaming_cname"] : $cfc["distro_streaming_dname"])."/cfx/st/".$file : "http".(($ssl) ? "s" : "")."://".(($cfc["distro_downloads_cname"]) ? $cfc["distro_downloads_cname"] : $cfc["distro_downloads_dname"])."/".$url_e_file;
850
- $cf_policy = '{"Statement":[{"Resource":"'.c_ws_plugin__s2member_utils_strings::esc_dq($cf_resource).'","Condition":{'.(($cf_ip_res) ? '"IpAddress":{"AWS:SourceIp":"'.c_ws_plugin__s2member_utils_strings::esc_dq($_SERVER["REMOTE_ADDR"]).'/32"},' : '').'"DateLessThan":{"AWS:EpochTime":'.(int)$cfc["expires"].'}}}]}';
851
852
- $cf_signature = c_ws_plugin__s2member_files_in::amazon_cf_rsa_sign($cf_policy);
853
- $cf_base64_url_safe_policy = c_ws_plugin__s2member_utils_strings::base64_url_safe_encode($cf_policy, array("+", "=", "/"), array("-", "_", "~"), false);
854
- $cf_base64_url_safe_signature = c_ws_plugin__s2member_utils_strings::base64_url_safe_encode($cf_signature, array("+", "=", "/"), array("-", "_", "~"), false);
855
856
- return add_query_arg(c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode_deep(array("Policy" => $cf_base64_url_safe_policy, "Signature" => $cf_base64_url_safe_signature, "Key-Pair-Id" => $cfc["private_key_id"]))), $cf_url);
857
- }
858
- /**
859
- * Auto-configures Amazon S3/CloudFront distros.
860
- *
861
- * @package s2Member\Files
862
- * @since 110926
863
- *
864
- * @return array Array containing a true `success` element on success, else a failure array.
865
- * Failure array will contain a failure `code`, and a failure `message`.
866
- */
867
- public static function amazon_cf_auto_configure_distros()
868
- {
869
- foreach($GLOBALS["WS_PLUGIN__"]["s2member"]["o"] as $option => $option_value)
870
- if(preg_match("/^amazon_cf_files_/", $option) && ($option = preg_replace("/^amazon_cf_files_/", "", $option)))
871
- $cfc[$option] = $option_value;
872
873
- $s3c["bucket"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"];
874
- $cfc["access_key"] = $s3c["access_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"];
875
- $cfc["secret_key"] = $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
876
877
- if /* We MUST have an Amazon S3 Bucket and Keys. */($s3c["bucket"] && $s3c["access_key"] && $s3c["secret_key"])
878
- {
879
- if /* We MUST have Amazon CloudFront Keys in order to auto-configure. */($cfc["private_key"] && $cfc["private_key_id"])
880
- {
881
- if(!$cfc["distro_downloads_id"] || ($cfc["distro_downloads_id"] && ($cf_get_response = c_ws_plugin__s2member_files_in::amazon_cf_get_distro($cfc["distro_downloads_id"], "downloads")) && ($cf_get_response["success"] || $cf_get_response["code"] === 404)))
882
{
883
- if(!$cfc["distro_downloads_id"] || ($cfc["distro_downloads_id"] && $cf_get_response && !$cf_get_response["success"] && $cf_get_response["code"] === 404))
884
- $cf_distro_downloads_clear = /* Clear, ready for a new one. */ true;
885
-
886
- else if($cfc["distro_downloads_id"] && $cf_get_response && $cf_get_response["success"] && !$cf_get_response["deployed"])
887
- return array("success" => false, "code" => -86, "message" => _x("Unable to delete existing Amazon CloudFront Downloads Distro. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
888
-
889
- else if($cfc["distro_downloads_id"] && $cf_get_response && $cf_get_response["success"] && $cf_get_response["deployed"] && ($cf_del_response = c_ws_plugin__s2member_files_in::amazon_cf_del_distro($cfc["distro_downloads_id"], $cf_get_response["etag"], $cf_get_response["xml"])) && $cf_del_response["success"])
890
- $cf_distro_downloads_clear = /* Clear, ready for a new one. */ true;
891
892
- else if(isset($cf_del_response["code"], $cf_del_response["message"]))
893
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
894
- return array("success" => false, "code" => $cf_del_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_del_response["message"]));
895
896
- if /* Successfully cleared? Ready for a new one? */(isset($cf_distro_downloads_clear) && $cf_distro_downloads_clear)
897
{
898
- unset /* Unset these before processing additional routines. Prevents problems in error reporting. */($cf_get_response, $cf_del_response);
899
-
900
- if(!$cfc["distro_streaming_id"] || ($cfc["distro_streaming_id"] && ($cf_get_response = c_ws_plugin__s2member_files_in::amazon_cf_get_distro($cfc["distro_streaming_id"], "streaming")) && ($cf_get_response["success"] || $cf_get_response["code"] === 404)))
901
{
902
- if(!$cfc["distro_streaming_id"] || ($cfc["distro_streaming_id"] && $cf_get_response && !$cf_get_response["success"] && $cf_get_response["code"] === 404))
903
- $cf_distro_streaming_clear = /* Clear, ready for a new one. */ true;
904
-
905
- else if($cfc["distro_streaming_id"] && $cf_get_response && $cf_get_response["success"] && !$cf_get_response["deployed"])
906
- return array("success" => false, "code" => -87, "message" => _x("Unable to delete existing Amazon CloudFront Streaming Distro. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
907
-
908
- else if($cfc["distro_streaming_id"] && $cf_get_response && $cf_get_response["success"] && $cf_get_response["deployed"] && ($cf_del_response = c_ws_plugin__s2member_files_in::amazon_cf_del_distro($cfc["distro_streaming_id"], $cf_get_response["etag"], $cf_get_response["xml"])) && $cf_del_response["success"])
909
- $cf_distro_streaming_clear = /* Clear, ready for a new one. */ true;
910
-
911
- else if(isset($cf_del_response["code"], $cf_del_response["message"]))
912
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
913
- return array("success" => false, "code" => $cf_del_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_del_response["message"]));
914
-
915
- if /* Successfully cleared? Ready for a new one? */(isset($cf_distro_streaming_clear) && $cf_distro_streaming_clear)
916
- {
917
- unset /* Unset these before processing additional routines. Prevents problems in error reporting. */($cf_get_response, $cf_del_response);
918
-
919
- if(!$cfc["distros_access_id"] || ($cfc["distros_access_id"] && ($cf_get_response = c_ws_plugin__s2member_files_in::amazon_cf_get_access_origin_identity($cfc["distros_access_id"])) && ($cf_get_response["success"] || $cf_get_response["code"] === 404)))
920
- {
921
- if(!$cfc["distros_access_id"] || ($cfc["distros_access_id"] && $cf_get_response && !$cf_get_response["success"] && $cf_get_response["code"] === 404))
922
- $cf_distros_access_clear = /* Clear, ready for a new one. */ true;
923
-
924
- else if($cfc["distros_access_id"] && $cf_get_response && $cf_get_response["success"] && ($cf_del_response = c_ws_plugin__s2member_files_in::amazon_cf_del_access_origin_identity($cfc["distros_access_id"], $cf_get_response["etag"], $cf_get_response["xml"])) && $cf_del_response["success"])
925
- $cf_distros_access_clear = /* Clear, ready for a new one. */ true;
926
-
927
- else if(isset($cf_del_response["code"], $cf_del_response["message"]))
928
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
929
- return array("success" => false, "code" => $cf_del_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_del_response["message"]));
930
-
931
- if /* Successfully cleared? Ready for a new one? */(isset($cf_distros_access_clear) && $cf_distros_access_clear)
932
- {
933
- unset /* Unset these before processing additional routines. Prevents problems in error reporting. */($cf_get_response, $cf_del_response);
934
-
935
- $cfc = array_merge($cfc, array("distros_access_id" => "", "distros_s3_access_id" => "", "distro_downloads_id" => "", "distro_downloads_dname" => "", "distro_streaming_id" => "", "distro_streaming_dname" => "", "distros_auto_config_status" => ""));
936
- $cf_options = array("ws_plugin__s2member_amazon_cf_files_distros_access_id" => "", "ws_plugin__s2member_amazon_cf_files_distros_s3_access_id" => "", "ws_plugin__s2member_amazon_cf_files_distro_downloads_id" => "", "ws_plugin__s2member_amazon_cf_files_distro_downloads_dname" => "", "ws_plugin__s2member_amazon_cf_files_distro_streaming_id" => "", "ws_plugin__s2member_amazon_cf_files_distro_streaming_dname" => "", "ws_plugin__s2member_amazon_cf_files_distros_auto_config_status" => "");
937
- c_ws_plugin__s2member_menu_pages::update_all_options($cf_options, true, false, false, false, false);
938
-
939
- if(($cf_response = c_ws_plugin__s2member_files_in::amazon_cf_create_distros_access_origin_identity()) && $cf_response["success"])
940
- {
941
- $cfc = array_merge($cfc, array("distros_access_id" => $cf_response["distros_access_id"], "distros_s3_access_id" => $cf_response["distros_s3_access_id"]));
942
- $cf_options = array("ws_plugin__s2member_amazon_cf_files_distros_access_id" => $cf_response["distros_access_id"], "ws_plugin__s2member_amazon_cf_files_distros_s3_access_id" => $cf_response["distros_s3_access_id"]);
943
- c_ws_plugin__s2member_menu_pages::update_all_options($cf_options, true, false, false, false, false);
944
-
945
- if(($cf_response = c_ws_plugin__s2member_files_in::amazon_cf_create_distro("downloads")) && $cf_response["success"])
946
- {
947
- $cfc = array_merge($cfc, array("distro_downloads_id" => $cf_response["distro_downloads_id"], "distro_downloads_dname" => $cf_response["distro_downloads_dname"]));
948
- $cf_options = array("ws_plugin__s2member_amazon_cf_files_distro_downloads_id" => $cf_response["distro_downloads_id"], "ws_plugin__s2member_amazon_cf_files_distro_downloads_dname" => $cf_response["distro_downloads_dname"]);
949
- c_ws_plugin__s2member_menu_pages::update_all_options($cf_options, true, false, false, false, false);
950
-
951
- if(($cf_response = c_ws_plugin__s2member_files_in::amazon_cf_create_distro("streaming")) && $cf_response["success"])
952
- {
953
- $cfc = array_merge($cfc, array("distro_streaming_id" => $cf_response["distro_streaming_id"], "distro_streaming_dname" => $cf_response["distro_streaming_dname"]));
954
- $cf_options = array("ws_plugin__s2member_amazon_cf_files_distro_streaming_id" => $cf_response["distro_streaming_id"], "ws_plugin__s2member_amazon_cf_files_distro_streaming_dname" => $cf_response["distro_streaming_dname"]);
955
- c_ws_plugin__s2member_menu_pages::update_all_options($cf_options, true, false, false, false, false);
956
-
957
- for($a = 1, $attempts = 4, $sleep = 2, sleep($sleep); $a <= $attempts; $a++, (($a <= $attempts) ? sleep($sleep) : null))
958
- /* Allow a generous propagation time here. Amazon's high-availability services do NOT guarantee real-time updates.
959
- Since we DO need a fully propagated Origin Access Identity now, we need to make several attempts at success.
960
- For further details, please see this thread: <https://forums.aws.amazon.com/message.jspa?messageID=42875>. */
961
- if(($s3_response = c_ws_plugin__s2member_files_in::amazon_s3_auto_configure_acls()) && $s3_response["success"])
962
- {
963
- $cfc = array_merge($cfc, array("distros_auto_config_status" => "configured"));
964
- $cf_options = array("ws_plugin__s2member_amazon_cf_files_distros_auto_config_status" => "configured");
965
- c_ws_plugin__s2member_menu_pages::update_all_options( /* Now configured! */$cf_options, true, false, false, false, false);
966
- return /* Successfully configured Amazon S3/CloudFront distros. */ array("success" => true, "code" => null, "message" => null);
967
- }
968
- if(isset($s3_response["code"], $s3_response["message"]))
969
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon S3 API call. Feel free to exclude `%s` if you like. */
970
- return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon S3 ACLs. %s", "s2member-admin", "s2member"), $s3_response["message"]));
971
-
972
- else // Else, we use a default error code and message.
973
- return array("success" => false, "code" => -88, "message" => _x("Unable to update existing Amazon S3 ACLs. Connection failed.", "s2member-admin", "s2member"));
974
- }
975
- else if(isset($cf_response["code"], $cf_response["message"]))
976
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
977
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
978
-
979
- else // Else, we use a default error code and message.
980
- return array("success" => false, "code" => -89, "message" => _x("Unable to create Amazon CloudFront Streaming Distro. Connection failed.", "s2member-admin", "s2member"));
981
- }
982
- else if(isset($cf_response["code"], $cf_response["message"]))
983
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
984
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
985
-
986
- else // Else, we use a default error code and message.
987
- return array("success" => false, "code" => -90, "message" => _x("Unable to create Amazon CloudFront Downloads Distro. Connection failed.", "s2member-admin", "s2member"));
988
- }
989
- else if(isset($cf_response["code"], $cf_response["message"]))
990
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
991
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
992
-
993
- else // Else, we use a default error code and message.
994
- return array("success" => false, "code" => -91, "message" => _x("Unable to create Amazon CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
995
- }
996
- else // Else, we use a default error code and message.
997
- return array("success" => false, "code" => -92, "message" => _x("Unable to clear existing Amazon CloudFront Origin Access Identity.", "s2member-admin", "s2member"));
998
- }
999
- else if(isset($cf_get_response["code"], $cf_get_response["message"]))
1000
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1001
- return array("success" => false, "code" => $cf_get_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_get_response["message"]));
1002
-
1003
- else // Else, we use a default error code and message.
1004
- return array("success" => false, "code" => -93, "message" => _x("Unable to acquire existing Amazon CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
1005
- }
1006
- else // Else, we use a default error code and message.
1007
- return array("success" => false, "code" => -94, "message" => _x("Unable to clear existing Amazon CloudFront Streaming Distro.", "s2member-admin", "s2member"));
1008
}
1009
- else if(isset($cf_get_response["code"], $cf_get_response["message"]))
1010
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1011
- return array("success" => false, "code" => $cf_get_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_get_response["message"]));
1012
1013
else // Else, we use a default error code and message.
1014
- return array("success" => false, "code" => -95, "message" => _x("Unable to acquire existing Amazon CloudFront Streaming Distro. Connection failed.", "s2member-admin", "s2member"));
1015
}
1016
else // Else, we use a default error code and message.
1017
- return array("success" => false, "code" => -96, "message" => _x("Unable to clear existing Amazon CloudFront Downloads Distro.", "s2member-admin", "s2member"));
1018
}
1019
- else if(isset($cf_get_response["code"], $cf_get_response["message"]))
1020
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1021
- return array("success" => false, "code" => $cf_get_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_get_response["message"]));
1022
1023
else // Else, we use a default error code and message.
1024
- return array("success" => false, "code" => -97, "message" => _x("Unable to acquire existing Amazon CloudFront Downloads Distro. Connection failed.", "s2member-admin", "s2member"));
1025
}
1026
else // Else, we use a default error code and message.
1027
- return array("success" => false, "code" => -98, "message" => _x("Unable to auto-configure Amazon CloudFront Distros. Incomplete Amazon CloudFront configuration options. Missing of one: Amazon CloudFront Private Key-Pair-ID, or Private Key file contents.", "s2member-admin", "s2member"));
1028
}
1029
else // Else, we use a default error code and message.
1030
- return array("success" => false, "code" => -99, "message" => _x("Unable to auto-configure Amazon S3/CloudFront Distros. Incomplete Amazon S3 configuration options. Missing one of: Amazon S3 Bucket, Access Key, or Secret Key. You must provide s2Member with an Amazon S3 configuration before enabling CloudFront.", "s2member-admin", "s2member"));
1031
}
1032
- /**
1033
- * Acquires an Amazon S3/CloudFront Access Origin Identity.
1034
- *
1035
- * @package s2Member\Files
1036
- * @since 110926
1037
- *
1038
- * @param string $access_id Required. An Origin Access ID.
1039
- * @return array Array containing a true `success` and `etag`, `xml` elements on success, else a failure array.
1040
- * Failure array will contain a failure `code`, and a failure `message`.
1041
- */
1042
- public static function amazon_cf_get_access_origin_identity($access_id = FALSE)
1043
- {
1044
- if /* Valid parameters? */($access_id && is_string($access_id))
1045
- {
1046
- foreach($GLOBALS["WS_PLUGIN__"]["s2member"]["o"] as $option => $option_value)
1047
- if(preg_match("/^amazon_cf_files_/", $option) && ($option = preg_replace("/^amazon_cf_files_/", "", $option)))
1048
- $cfc[$option] = $option_value;
1049
1050
- $s3c["bucket"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"];
1051
- $cfc["access_key"] = $s3c["access_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"];
1052
- $cfc["secret_key"] = $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
1053
1054
- $cf_domain = "cloudfront.amazonaws.com";
1055
- $cf_date = gmdate("D, d M Y H:i:s")." GMT";
1056
- $cf_location = "/2010-11-01/origin-access-identity/cloudfront/".$access_id;
1057
- $cf_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_cf_sign($cf_date));
1058
- $cf_args = array("method" => "GET", "redirection" => 5, "headers" => array("Host" => $cf_domain, "Date" => $cf_date, "Authorization" => "AWS ".$cfc["access_key"].":".$cf_signature));
1059
1060
- if(($cf_response = c_ws_plugin__s2member_utils_urls::remote("https://".$cf_domain.$cf_location, false, array_merge($cf_args, array("timeout" => 20)), "array")) && (($cf_response["code"] === 404 && $cf_response["message"]) || ($cf_response["code"] === 200 && !empty($cf_response["headers"]["etag"]) && !empty($cf_response["body"]))))
1061
- {
1062
- if($cf_response["code"] === 200 && !empty($cf_response["headers"]["etag"]) && !empty($cf_response["body"]))
1063
- return array("success" => true, "code" => null, "message" => null, "etag" => trim($cf_response["headers"]["etag"]), "xml" => trim($cf_response["body"]));
1064
1065
- else /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1066
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Existing Amazon CloudFront Origin Access Identity NOT found. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1067
- }
1068
- else if(isset($cf_response["code"], $cf_response["message"]))
1069
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1070
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1071
1072
- else // Else, we use a default error code and message.
1073
- return array("success" => false, "code" => -98, "message" => _x("Unable to acquire existing Amazon CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
1074
- }
1075
- else // Else, we use a default error code and message.
1076
- return array("success" => false, "code" => -99, "message" => _x("Unable to acquire existing Amazon CloudFront Origin Access Identity. Invalid Access ID.", "s2member-admin", "s2member"));
1077
- }
1078
- /**
1079
- * Deletes an Amazon S3/CloudFront Access Origin Identity.
1080
- *
1081
- * @package s2Member\Files
1082
- * @since 110926
1083
- *
1084
- * @param string $access_id Required. An Origin Access ID.
1085
- * @param string $access_id_etag Required. An Origin Access ETag header.
1086
- * @param string $access_id_xml Required. An Origin Access Identity's XML configuration.
1087
- * @return array Array containing a true `success` element on success, else a failure array.
1088
- * Failure array will contain a failure `code`, and a failure `message`.
1089
- */
1090
- public static function amazon_cf_del_access_origin_identity($access_id = FALSE, $access_id_etag = FALSE, $access_id_xml = FALSE)
1091
- {
1092
- if($access_id && is_string($access_id) && $access_id_etag && is_string($access_id_etag) && $access_id_xml && is_string($access_id_xml))
1093
- {
1094
- foreach($GLOBALS["WS_PLUGIN__"]["s2member"]["o"] as $option => $option_value)
1095
- if(preg_match("/^amazon_cf_files_/", $option) && ($option = preg_replace("/^amazon_cf_files_/", "", $option)))
1096
- $cfc[$option] = $option_value;
1097
1098
- $s3c["bucket"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"];
1099
- $cfc["access_key"] = $s3c["access_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"];
1100
- $cfc["secret_key"] = $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
1101
1102
- $cf_domain = "cloudfront.amazonaws.com";
1103
- $cf_date = gmdate("D, d M Y H:i:s")." GMT";
1104
- $cf_location = "/2010-11-01/origin-access-identity/cloudfront/".$access_id;
1105
- $cf_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_cf_sign($cf_date));
1106
- $cf_args = array("method" => "DELETE", "redirection" => 5, "headers" => array("Host" => $cf_domain, "Date" => $cf_date, "If-Match" => $access_id_etag, "Authorization" => "AWS ".$cfc["access_key"].":".$cf_signature));
1107
1108
- if(($cf_response = c_ws_plugin__s2member_utils_urls::remote("https://".$cf_domain.$cf_location, false, array_merge($cf_args, array("timeout" => 20)), "array")) && ($cf_response["code"] === 200 || $cf_response["code"] === 204 /* Deleted. */))
1109
- return /* Deleted successfully. */ array("success" => true, "code" => null, "message" => null);
1110
1111
- else if(isset($cf_response["code"], $cf_response["message"]))
1112
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1113
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1114
1115
- else // Else, we use a default error code and message.
1116
- return array("success" => false, "code" => -98, "message" => _x("Unable to delete existing Amazon CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
1117
- }
1118
- else // Else, we use a default error code and message.
1119
- return array("success" => false, "code" => -99, "message" => _x("Unable to delete existing Amazon CloudFront Origin Access Identity. Invalid Access ID, ETag, or XML config.", "s2member-admin", "s2member"));
1120
- }
1121
- /**
1122
- * Creates an Amazon S3/CloudFront Access Origin Identity for all Distros.
1123
- *
1124
- * @package s2Member\Files
1125
- * @since 110926
1126
- *
1127
- * @return array Array containing a true `success` and `distros_access_id`, `distros_s3_access_id` elements on success, else a failure array.
1128
- * Failure array will contain a failure `code`, and a failure `message`.
1129
- */
1130
- public static function amazon_cf_create_distros_access_origin_identity()
1131
{
1132
- foreach($GLOBALS["WS_PLUGIN__"]["s2member"]["o"] as $option => $option_value)
1133
- if(preg_match("/^amazon_cf_files_/", $option) && ($option = preg_replace("/^amazon_cf_files_/", "", $option)))
1134
$cfc[$option] = $option_value;
1135
1136
- $s3c["bucket"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"];
1137
- $cfc["access_key"] = $s3c["access_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"];
1138
- $cfc["secret_key"] = $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
1139
1140
- $cf_domain = "cloudfront.amazonaws.com";
1141
- $cf_date = gmdate("D, d M Y H:i:s")." GMT";
1142
- $cf_location = "/2010-11-01/origin-access-identity/cloudfront";
1143
- $cf_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_cf_sign($cf_date));
1144
- $cf_distros_access_reference = time().".".md5("access".$s3c["bucket"].$s3c["access_key"].$s3c["secret_key"].$cfc["private_key"].$cfc["private_key_id"]);
1145
- $cf_distros_access_xml = '<?xml version="1.0" encoding="UTF-8"?><CloudFrontOriginAccessIdentityConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-11-01/"><CallerReference>'.esc_html($cf_distros_access_reference).'</CallerReference><Comment>'.esc_html(sprintf(_x("Created by s2Member, for S3 Bucket: %s.", "s2member-admin", "s2member"), $s3c["bucket"])).'</Comment></CloudFrontOriginAccessIdentityConfig>';
1146
- $cf_args = array("method" => "POST", "redirection" => 5, "body" => $cf_distros_access_xml, "headers" => array("Host" => $cf_domain, "Content-Type" => "application/xml", "Date" => $cf_date, "Authorization" => "AWS ".$cfc["access_key"].":".$cf_signature));
1147
1148
- if(($cf_response = c_ws_plugin__s2member_utils_urls::remote("https://".$cf_domain.$cf_location, false, array_merge($cf_args, array("timeout" => 20)), "array")) && ($cf_response["code"] === 200 || $cf_response["code"] === 201 /* Created. */))
1149
- {
1150
- if(preg_match("/\<CloudFrontOriginAccessIdentity.*?\>(.+?)\<\/CloudFrontOriginAccessIdentity\>/is", $cf_response["body"], $cf_distros_access_tag) && preg_match("/\<Id\>(.+?)\<\/Id\>/is", $cf_distros_access_tag[1], $cf_distros_access_id_tag) && preg_match("/\<S3CanonicalUserId\>(.+?)\<\/S3CanonicalUserId\>/is", $cf_distros_access_tag[1], $cf_distros_s3_access_id_tag))
1151
- return array("success" => true, "code" => null, "message" => null, "distros_access_id" => trim($cf_distros_access_id_tag[1]), "distros_s3_access_id" => trim($cf_distros_s3_access_id_tag[1]));
1152
1153
- else // Else, we use a default error code and message.
1154
- return array("success" => false, "code" => -98, "message" => _x("Unable to create/read Amazon CloudFront Origin Access Identity. Unexpected response.", "s2member-admin", "s2member"));
1155
- }
1156
- else if(isset($cf_response["code"], $cf_response["message"]))
1157
/* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1158
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1159
1160
else // Else, we use a default error code and message.
1161
- return array("success" => false, "code" => -99, "message" => _x("Unable to create Amazon CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
1162
}
1163
- /**
1164
- * Acquires an Amazon S3/CloudFront Distro.
1165
- *
1166
- * @package s2Member\Files
1167
- * @since 110926
1168
- *
1169
- * @param string $distro_id Required. A Distro ID.
1170
- * @param string $distro_type Required: `downloads|streaming`.
1171
- * @return array Array containing a true `success` and `etag`, `xml`, `deployed` elements on success, else a failure array.
1172
- * Failure array will contain a failure `code`, and a failure `message`.
1173
- */
1174
- public static function amazon_cf_get_distro($distro_id = FALSE, $distro_type = FALSE)
1175
- {
1176
- if($distro_id && is_string($distro_id) && $distro_type && is_string($distro_type) && in_array($distro_type, array("downloads", "streaming")))
1177
- {
1178
- foreach($GLOBALS["WS_PLUGIN__"]["s2member"]["o"] as $option => $option_value)
1179
- if(preg_match("/^amazon_cf_files_/", $option) && ($option = preg_replace("/^amazon_cf_files_/", "", $option)))
1180
- $cfc[$option] = $option_value;
1181
-
1182
- $s3c["bucket"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"];
1183
- $cfc["access_key"] = $s3c["access_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"];
1184
- $cfc["secret_key"] = $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
1185
-
1186
- $cf_domain = "cloudfront.amazonaws.com";
1187
- $cf_date = gmdate("D, d M Y H:i:s")." GMT";
1188
- $cf_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_cf_sign($cf_date));
1189
- $cf_location = ($distro_type === "streaming") ? "/2010-11-01/streaming-distribution/".$distro_id : "/2010-11-01/distribution/".$distro_id;
1190
- $cf_args = array("method" => "GET", "redirection" => 5, "headers" => array("Host" => $cf_domain, "Date" => $cf_date, "Authorization" => "AWS ".$cfc["access_key"].":".$cf_signature));
1191
-
1192
- if(($cf_response = c_ws_plugin__s2member_utils_urls::remote("https://".$cf_domain.$cf_location, false, array_merge($cf_args, array("timeout" => 20)), "array")) && (($cf_response["code"] === 404 && $cf_response["message"]) || ($cf_response["code"] === 200 && !empty($cf_response["headers"]["etag"]) && !empty($cf_response["body"]))))
1193
- {
1194
- if($cf_response["code"] === 200 && !empty($cf_response["headers"]["etag"]) && !empty($cf_response["body"]))
1195
- return array("success" => true, "code" => null, "message" => null, "etag" => trim($cf_response["headers"]["etag"]), "xml" => trim($cf_response["body"]), "deployed" => ((stripos($cf_response["body"], "<Status>Deployed</Status>") !== false) ? true : false));
1196
-
1197
- else /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1198
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Existing Amazon CloudFront Distro NOT found. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1199
- }
1200
- else if(isset($cf_response["code"], $cf_response["message"]))
1201
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1202
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1203
1204
- else // Else, we use a default error code and message.
1205
- return array("success" => false, "code" => -98, "message" => _x("Unable to acquire existing Amazon CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1206
- }
1207
- else // Else, we use a default error code and message.
1208
- return array("success" => false, "code" => -99, "message" => _x("Unable to acquire existing Amazon CloudFront Distro. Invalid Distro ID and/or Distro type.", "s2member-admin", "s2member"));
1209
- }
1210
- /**
1211
- * Disables an Amazon S3/CloudFront Distro.
1212
- *
1213
- * @package s2Member\Files
1214
- * @since 110926
1215
- *
1216
- * @param string $distro_id Required. A Distro ID.
1217
- * @param string $distro_id_etag Required. A Distro ETag header.
1218
- * @param string $distro_id_xml Required. A Distro's XML configuration.
1219
- * @return array Array containing a true `success` and `etag`, `xml`, `deployed` elements on success, else a failure array.
1220
- * Failure array will contain a failure `code`, and a failure `message`.
1221
- */
1222
- public static function amazon_cf_disable_distro($distro_id = FALSE, $distro_id_etag = FALSE, $distro_id_xml = FALSE)
1223
{
1224
- if($distro_id && is_string($distro_id) && $distro_id_etag && is_string($distro_id_etag) && $distro_id_xml && is_string($distro_id_xml) && ($distro_id_type = (stripos($distro_id_xml, "<StreamingDistribution") !== false) ? "streaming" : ((stripos($distro_id_xml, "<Distribution") !== false) ? "downloads" : false)) && preg_match("/\<CallerReference\>(.+?)\<\/CallerReference\>/is", $distro_id_xml, $distro_id_reference_tag) && ($distro_id_reference = $distro_id_reference_tag[1]))
1225
- {
1226
- if /* Only if it has NOT already been disabled. We do NOT need to do it again. */(stripos($distro_id_xml, "<Enabled>false</Enabled>") === false)
1227
- {
1228
- if /* Check distro status before we even begin processing. */(stripos($distro_id_xml, "<Status>Deployed</Status>") !== false)
1229
- {
1230
- foreach($GLOBALS["WS_PLUGIN__"]["s2member"]["o"] as $option => $option_value)
1231
- if(preg_match("/^amazon_cf_files_/", $option) && ($option = preg_replace("/^amazon_cf_files_/", "", $option)))
1232
- $cfc[$option] = $option_value;
1233
-
1234
- $s3c["bucket"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"];
1235
- $cfc["access_key"] = $s3c["access_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"];
1236
- $cfc["secret_key"] = $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
1237
-
1238
- $cf_domain = "cloudfront.amazonaws.com";
1239
- $cf_date = gmdate("D, d M Y H:i:s")." GMT";
1240
- $cf_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_cf_sign($cf_date));
1241
- $cf_location = ($distro_id_type === "streaming") ? "/2010-11-01/streaming-distribution/".$distro_id."/config" : "/2010-11-01/distribution/".$distro_id."/config";
1242
- $cf_distro_xml = ($distro_id_type === "streaming") ? '<?xml version="1.0" encoding="UTF-8"?><StreamingDistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-11-01/"><S3Origin><DNSName>'.esc_html($s3c["bucket"]).'.s3.amazonaws.com</DNSName></S3Origin><CallerReference>'.esc_html($distro_id_reference).'</CallerReference><Enabled>false</Enabled><TrustedSigners><Self/></TrustedSigners></StreamingDistributionConfig>' : '<?xml version="1.0" encoding="UTF-8"?><DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-11-01/"><S3Origin><DNSName>'.esc_html($s3c["bucket"]).'.s3.amazonaws.com</DNSName></S3Origin><CallerReference>'.esc_html($distro_id_reference).'</CallerReference><Enabled>false</Enabled><TrustedSigners><Self/></TrustedSigners></DistributionConfig>';
1243
- $cf_args = array("method" => "PUT", "redirection" => 5, "body" => $cf_distro_xml, "headers" => array("Host" => $cf_domain, "Content-Type" => "application/xml", "Date" => $cf_date, "If-Match" => $distro_id_etag, "Authorization" => "AWS ".$cfc["access_key"].":".$cf_signature));
1244
-
1245
- if(($cf_response = c_ws_plugin__s2member_utils_urls::remote("https://".$cf_domain.$cf_location, false, array_merge($cf_args, array("timeout" => 20)), "array")) && $cf_response["code"] === 200 && !empty($cf_response["headers"]["etag"]) && !empty($cf_response["body"]))
1246
- return array("success" => true, "code" => null, "message" => null, "etag" => trim($cf_response["headers"]["etag"]), "xml" => trim($cf_response["body"]), "deployed" => ((stripos($cf_response["body"], "<Status>Deployed</Status>") !== false) ? true : false));
1247
1248
- else if(isset($cf_response["code"], $cf_response["message"]))
1249
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1250
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to disable existing Amazon CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1251
1252
- else // Else, we use a default error code and message.
1253
- return array("success" => false, "code" => -97, "message" => _x("Unable to disable existing Amazon CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1254
- }
1255
- else // Else, we use a default error code and message.
1256
- return array("success" => false, "code" => -98, "message" => _x("Existing Amazon CloudFront Distro cannot be disabled at this time. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
1257
- }
1258
- else // Else, we use a default error code and message.
1259
- return array("success" => true, "code" => null, "message" => null, "etag" => $distro_id_etag, "xml" => $distro_id_xml, "deployed" => ((stripos($distro_id_xml, "<Status>Deployed</Status>") !== false) ? true : false));
1260
- }
1261
else // Else, we use a default error code and message.
1262
- return array("success" => false, "code" => -99, "message" => _x("Unable to disable existing Amazon CloudFront Distro. Invalid Distro ID, ETag, or XML config.", "s2member-admin", "s2member"));
1263
}
1264
- /**
1265
- * Deletes an Amazon S3/CloudFront Distro.
1266
- *
1267
- * @package s2Member\Files
1268
- * @since 110926
1269
- *
1270
- * @param string $distro_id Required. A Distro ID.
1271
- * @param string $distro_id_etag Required. A Distro ETag header.
1272
- * @param string $distro_id_xml Required. A Distro's XML configuration.
1273
- * @return array Array containing a true `success` element on success, else a failure array.
1274
- * Failure array will contain a failure `code`, and a failure `message`.
1275
- */
1276
- public static function amazon_cf_del_distro($distro_id = FALSE, $distro_id_etag = FALSE, $distro_id_xml = FALSE)
1277
- {
1278
- if($distro_id && is_string($distro_id) && $distro_id_etag && is_string($distro_id_etag) && $distro_id_xml && is_string($distro_id_xml) && ($distro_id_type = (stripos($distro_id_xml, "<StreamingDistribution") !== false) ? "streaming" : ((stripos($distro_id_xml, "<Distribution") !== false) ? "downloads" : false)) && preg_match("/\<CallerReference\>(.+?)\<\/CallerReference\>/is", $distro_id_xml, $distro_id_reference_tag) && ($distro_id_reference = $distro_id_reference_tag[1]))
1279
- {
1280
- if /* Check distro status before we even begin processing this deletion. */(stripos($distro_id_xml, "<Status>Deployed</Status>") !== false)
1281
- {
1282
- if(($cf_response = c_ws_plugin__s2member_files_in::amazon_cf_disable_distro($distro_id, $distro_id_etag, $distro_id_xml)) && $cf_response["success"])
1283
- {
1284
- if(($cf_response = c_ws_plugin__s2member_files_in::amazon_cf_get_distro($distro_id, $distro_id_type)) && $cf_response["success"] && $cf_response["deployed"])
1285
- {
1286
- foreach($GLOBALS["WS_PLUGIN__"]["s2member"]["o"] as $option => $option_value)
1287
- if(preg_match("/^amazon_cf_files_/", $option) && ($option = preg_replace("/^amazon_cf_files_/", "", $option)))
1288
- $cfc[$option] = $option_value;
1289
-
1290
- $s3c["bucket"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"];
1291
- $cfc["access_key"] = $s3c["access_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"];
1292
- $cfc["secret_key"] = $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
1293
-
1294
- $cf_domain = "cloudfront.amazonaws.com";
1295
- $cf_date = gmdate("D, d M Y H:i:s")." GMT";
1296
- $cf_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_cf_sign($cf_date));
1297
- $cf_location = ($distro_id_type === "streaming") ? "/2010-11-01/streaming-distribution/".$distro_id : "/2010-11-01/distribution/".$distro_id;
1298
- $cf_args = array("method" => "DELETE", "redirection" => 5, "headers" => array("Host" => $cf_domain, "Date" => $cf_date, "If-Match" => $cf_response["etag"], "Authorization" => "AWS ".$cfc["access_key"].":".$cf_signature));
1299
-
1300
- if(($cf_response = c_ws_plugin__s2member_utils_urls::remote("https://".$cf_domain.$cf_location, false, array_merge($cf_args, array("timeout" => 20)), "array")) && ($cf_response["code"] === 200 || $cf_response["code"] === 204 /* Deleted. */))
1301
- return /* Deleted successfully. */ array("success" => true, "code" => null, "message" => null);
1302
-
1303
- else if(isset($cf_response["code"], $cf_response["message"]))
1304
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1305
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1306
-
1307
- else // Else, we use a default error code and message.
1308
- return array("success" => false, "code" => -94, "message" => _x("Unable to delete existing Amazon CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1309
- }
1310
- else if(isset($cf_response["success"], $cf_response["deployed"]) && $cf_response["success"] && !$cf_response["deployed"])
1311
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1312
- return array("success" => false, "code" => -95, "message" => _x("Existing Amazon CloudFront Distro cannot be deleted at this time. Still in a `pending` state after having been disabled by s2Member. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
1313
-
1314
- else if(isset($cf_response["code"], $cf_response["message"]))
1315
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1316
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to check status of existing Amazon CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1317
1318
- else // Else, we use a default error code and message.
1319
- return array("success" => false, "code" => -96, "message" => _x("Unable to check status of existing Amazon CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1320
- }
1321
- else if(isset($cf_response["code"], $cf_response["message"]))
1322
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1323
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to disable existing Amazon CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1324
1325
- else // Else, we use a default error code and message.
1326
- return array("success" => false, "code" => -97, "message" => _x("Unable to disable existing Amazon CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1327
- }
1328
- else // Else, we use a default error code and message.
1329
- return array("success" => false, "code" => -98, "message" => _x("Existing Amazon CloudFront Distro cannot be deleted at this time. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
1330
- }
1331
else // Else, we use a default error code and message.
1332
- return array("success" => false, "code" => -99, "message" => _x("Unable to delete existing Amazon CloudFront Distro. Invalid Distro ID or ETag.", "s2member-admin", "s2member"));
1333
}
1334
- /**
1335
- * Creates an Amazon S3/CloudFront Distro.
1336
- *
1337
- * @package s2Member\Files
1338
- * @since 110926
1339
- *
1340
- * @param string $distro_type Required: `downloads|streaming`.
1341
- * @return array Array containing a true `success` and `distro_[distro_type]_id`, `distro_[distro_type]_dname` elements on success, else a failure array.
1342
- * Failure array will contain a failure `code`, and a failure `message`.
1343
- */
1344
- public static function amazon_cf_create_distro($distro_type = FALSE)
1345
{
1346
- if($distro_type && is_string($distro_type) && in_array($distro_type, array("downloads", "streaming")))
1347
- {
1348
- foreach($GLOBALS["WS_PLUGIN__"]["s2member"]["o"] as $option => $option_value)
1349
- if(preg_match("/^amazon_cf_files_/", $option) && ($option = preg_replace("/^amazon_cf_files_/", "", $option)))
1350
- $cfc[$option] = $option_value;
1351
-
1352
- $s3c["bucket"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"];
1353
- $cfc["access_key"] = $s3c["access_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"];
1354
- $cfc["secret_key"] = $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
1355
-
1356
- $cf_domain = "cloudfront.amazonaws.com";
1357
- $cf_date = gmdate("D, d M Y H:i:s")." GMT";
1358
- $cf_signature = base64_encode(c_ws_plugin__s2member_files_in::amazon_cf_sign($cf_date));
1359
-
1360
- if /* Create a `downloads` Distro? This uses a different XML schema. */($distro_type === "downloads")
1361
- {
1362
- $cf_location = /* Create distro. */ "/2010-11-01/distribution";
1363
- $cf_distro_downloads_reference = time().".".md5("downloads".$s3c["bucket"].$s3c["access_key"].$s3c["secret_key"].$cfc["private_key"].$cfc["private_key_id"].$cfc["distro_downloads_cname"]);
1364
- $cf_distro_downloads_xml = '<?xml version="1.0" encoding="UTF-8"?><DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-11-01/"><S3Origin><DNSName>'.esc_html($s3c["bucket"]).'.s3.amazonaws.com</DNSName><OriginAccessIdentity>origin-access-identity/cloudfront/'.esc_html($cfc["distros_access_id"]).'</OriginAccessIdentity></S3Origin><CallerReference>'.esc_html($cf_distro_downloads_reference).'</CallerReference>'.(($cfc["distro_downloads_cname"]) ? '<CNAME>'.esc_html($cfc["distro_downloads_cname"]).'</CNAME>' : '').'<Comment>'.esc_html(sprintf(_x("Created by s2Member, for S3 Bucket: %s.", "s2member-admin", "s2member"), $s3c["bucket"])).'</Comment><Enabled>true</Enabled><DefaultRootObject>index.html</DefaultRootObject><TrustedSigners><Self/></TrustedSigners></DistributionConfig>';
1365
- $cf_args = array("method" => "POST", "redirection" => 5, "body" => $cf_distro_downloads_xml, "headers" => array("Host" => $cf_domain, "Content-Type" => "application/xml", "Date" => $cf_date, "Authorization" => "AWS ".$cfc["access_key"].":".$cf_signature));
1366
-
1367
- if(($cf_response = c_ws_plugin__s2member_utils_urls::remote("https://".$cf_domain.$cf_location, false, array_merge($cf_args, array("timeout" => 20)), "array")) && ($cf_response["code"] === 200 || $cf_response["code"] === 201 /* Created. */))
1368
- {
1369
- if(preg_match("/\<Distribution.*?\>(.+?)\<\/Distribution\>/is", $cf_response["body"], $cf_distro_downloads_tag) && preg_match("/\<Id\>(.+?)\<\/Id\>/is", $cf_distro_downloads_tag[1], $cf_distro_downloads_id_tag) && preg_match("/\<DomainName\>(.+?)\<\/DomainName\>/is", $cf_distro_downloads_tag[1], $cf_distro_downloads_dname_tag))
1370
- return array("success" => true, "code" => null, "message" => null, "distro_downloads_id" => trim($cf_distro_downloads_id_tag[1]), "distro_downloads_dname" => trim($cf_distro_downloads_dname_tag[1]));
1371
1372
- else // Else, we use a default error code and message.
1373
- return array("success" => false, "code" => -97, "message" => _x("Unable to create/read Amazon CloudFront Downloads Distro. Unexpected response.", "s2member-admin", "s2member"));
1374
- }
1375
- else if(isset($cf_response["code"], $cf_response["message"]))
1376
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1377
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1378
-
1379
- else // Else, we use a default error code and message.
1380
- return array("success" => false, "code" => -98, "message" => _x("Unable to create Amazon CloudFront Downloads Distro. Connection failed.", "s2member-admin", "s2member"));
1381
- }
1382
-
1383
- else if /* Create a `streaming` Distro? A different XML schema. */($distro_type === "streaming")
1384
- {
1385
- $cf_location = /* Create streaming distro. */ "/2010-11-01/streaming-distribution";
1386
- $cf_distro_streaming_reference = time().".".md5("streaming".$s3c["bucket"].$s3c["access_key"].$s3c["secret_key"].$cfc["private_key"].$cfc["private_key_id"].$cfc["distro_streaming_cname"]);
1387
- $cf_distro_streaming_xml = '<?xml version="1.0" encoding="UTF-8"?><StreamingDistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-11-01/"><S3Origin><DNSName>'.esc_html($s3c["bucket"]).'.s3.amazonaws.com</DNSName><OriginAccessIdentity>origin-access-identity/cloudfront/'.esc_html($cfc["distros_access_id"]).'</OriginAccessIdentity></S3Origin><CallerReference>'.esc_html($cf_distro_streaming_reference).'</CallerReference>'.(($cfc["distro_streaming_cname"]) ? '<CNAME>'.esc_html($cfc["distro_streaming_cname"]).'</CNAME>' : '').'<Comment>'.esc_html(sprintf(_x("Created by s2Member, for S3 Bucket: %s.", "s2member-admin", "s2member"), $s3c["bucket"])).'</Comment><Enabled>true</Enabled><DefaultRootObject>index.html</DefaultRootObject><TrustedSigners><Self/></TrustedSigners></StreamingDistributionConfig>';
1388
- $cf_args = array("method" => "POST", "redirection" => 5, "body" => $cf_distro_streaming_xml, "headers" => array("Host" => $cf_domain, "Content-Type" => "application/xml", "Date" => $cf_date, "Authorization" => "AWS ".$cfc["access_key"].":".$cf_signature));
1389
-
1390
- if(($cf_response = c_ws_plugin__s2member_utils_urls::remote("https://".$cf_domain.$cf_location, false, array_merge($cf_args, array("timeout" => 20)), "array")) && ($cf_response["code"] === 200 || $cf_response["code"] === 201 /* Created. */))
1391
- {
1392
- if(preg_match("/\<StreamingDistribution.*?\>(.+?)\<\/StreamingDistribution\>/is", $cf_response["body"], $cf_distro_streaming_tag) && preg_match("/\<Id\>(.+?)\<\/Id\>/is", $cf_distro_streaming_tag[1], $cf_distro_streaming_id_tag) && preg_match("/\<DomainName\>(.+?)\<\/DomainName\>/is", $cf_distro_streaming_tag[1], $cf_distro_streaming_dname_tag))
1393
- return array("success" => true, "code" => null, "message" => null, "distro_streaming_id" => trim($cf_distro_streaming_id_tag[1]), "distro_streaming_dname" => trim($cf_distro_streaming_dname_tag[1]));
1394
-
1395
- else // Else, we use a default error code and message.
1396
- return array("success" => false, "code" => -97, "message" => _x("Unable to create/read Amazon CloudFront Streaming Distro. Unexpected response.", "s2member-admin", "s2member"));
1397
- }
1398
- else if(isset($cf_response["code"], $cf_response["message"]))
1399
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1400
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1401
-
1402
- else // Else, we use a default error code and message.
1403
- return array("success" => false, "code" => -98, "message" => _x("Unable to create Amazon CloudFront Streaming Distro. Connection failed.", "s2member-admin", "s2member"));
1404
- }
1405
- }
1406
else // Else, we use a default error code and message.
1407
- return array("success" => false, "code" => -99, "message" => _x("Unable to create Amazon CloudFront Distro. Invalid Distro type.", "s2member-admin", "s2member"));
1408
}
1409
}
1410
}
1411
- ?>
1
<?php
2
/**
3
+ * File Download routines for s2Member (inner processing routines).
4
+ *
5
+ * Copyright: © 2009-2011
6
+ * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
7
+ * (coded in the USA)
8
+ *
9
+ * Released under the terms of the GNU General Public License.
10
+ * You should have received a copy of the GNU General Public License,
11
+ * along with this software. In the main directory, see: /licensing/
12
+ * If not, see: {@link http://www.gnu.org/licenses/}.
13
+ *
14
+ * @package s2Member\Files
15
+ * @since 3.5
16
+ */
17
+ if(realpath(__FILE__) === realpath($_SERVER['SCRIPT_FILENAME']))
18
+ exit('Do not access this file directly.');
19
+
20
+ if(!class_exists('c_ws_plugin__s2member_files_in'))
21
+ {
22
+ /**
23
+ * File Download routines for s2Member (inner processing routines).
24
+ *
25
+ * @package s2Member\Files
26
+ * @since 3.5
27
+ */
28
+ class c_ws_plugin__s2member_files_in
29
{
30
/**
31
+ * Handles Download Access permissions.
32
+ *
33
+ * @package s2Member\Files
34
+ * @since 3.5
35
+ *
36
+ * @attaches-to ``add_action('init');``
37
+ * @also-called-by API Function {@link s2Member\API_Functions\s2member_file_download_url()}, w/ ``$create_file_download_url`` param.
38
+ *
39
+ * @param null|array $create_file_download_url Optional. If this function is called directly, we can pass arguments through this array.
40
+ * Possible array elements: `file_download` *(required)*, `file_download_key`, `file_stream`, `file_inline`, `file_storage`, `file_remote`, `file_ssl`, `file_rewrite`, `file_rewrite_base`, `skip_confirmation`, `url_to_storage_source`, `count_against_user`, `check_user`.
41
+ *
42
+ * @return null|string If called directly with ``$create_file_download_url``, returns a string with the URL, based on configuration.
43
+ * Else, this function may exit script execution after serving a File Download.
44
+ */
45
+ public static function check_file_download_access($create_file_download_url = NULL)
46
+ {
47
+ foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $__v;
48
+ do_action('ws_plugin__s2member_before_file_download_access', get_defined_vars());
49
+ unset($__refs, $__v); // Housekeeping.
50
+
51
+ $_g = !empty($_GET) ? $_GET : array();
52
+ $_g = c_ws_plugin__s2member_utils_strings::trim_deep(stripslashes_deep($_g));
53
+
54
+ $creating = (is_array($create = $create_file_download_url)) ? TRUE : FALSE; // Creating URL?
55
+ $serving = (!$creating) ? TRUE : FALSE; // If NOT creating a File Download URL, we're serving one.
56
+ $serving_range = $range = FALSE; // Default values (so these variables DO get defined at all times).
57
+
58
+ if($serving) // If we're serving, let's see if we're serving a byte-range request here.
59
{
60
+ $range = (string)@$_SERVER['HTTP_RANGE'];
61
+
62
+ if(!$range && function_exists('apache_request_headers'))
63
+ {
64
+ foreach((array)apache_request_headers() as $_header => $_value)
65
+ // Note: ``apache_request_headers()`` works in FastCGI too, starting w/ PHP v5.4.
66
+ if(is_string($_header) && strcasecmp($_header, 'range') === 0)
67
+ $range = $_value;
68
+ }
69
+ unset($_header, $_value); // Housekeeping.
70
+
71
+ if($range) $serving_range = TRUE;
72
+ }
73
+ $req['file_download'] = ($creating) ? @$create['file_download'] : @$_g['s2member_file_download'];
74
+ $req['file_download_key'] = ($creating) ? @$create['file_download_key'] : @$_g['s2member_file_download_key'];
75
+
76
+ $req['file_stream'] = ($creating) ? @$create['file_stream'] : @$_g['s2member_file_stream'];
77
+ $req['file_inline'] = ($creating) ? @$create['file_inline'] : @$_g['s2member_file_inline'];
78
+ $req['file_storage'] = ($creating) ? @$create['file_storage'] : @$_g['s2member_file_storage'];
79
+ $req['file_remote'] = ($creating) ? @$create['file_remote'] : @$_g['s2member_file_remote'];
80
+ $req['file_ssl'] = ($creating) ? @$create['file_ssl'] : @$_g['s2member_file_ssl'];
81
+
82
+ $req['file_rewrite'] = ($creating) ? @$create['file_rewrite'] : NULL;
83
+ $req['file_rewrite_base'] = ($creating) ? @$create['file_rewrite_base'] : NULL;
84
+
85
+ $req['skip_confirmation'] = ($creating) ? @$create['skip_confirmation'] : NULL;
86
+ $req['url_to_storage_source'] = ($creating) ? @$create['url_to_storage_source'] : NULL;
87
+ $req['count_against_user'] = ($creating) ? @$create['count_against_user'] : NULL;
88
+ $req['check_user'] = ($creating) ? @$create['check_user'] : NULL;
89
+
90
+ if($req['file_download'] && is_string($req['file_download']) && ($req['file_download'] = trim($req['file_download'], '/')))
91
+ if(strpos($req['file_download'], '..') === FALSE && strpos(basename($req['file_download']), '.') !== 0)
92
+ {
93
+ $using_amazon_cf_storage = ((!$req['file_storage'] || strcasecmp((string)$req['file_storage'], 'cf') === 0) && c_ws_plugin__s2member_utils_conds::using_amazon_cf_storage()) ? TRUE : FALSE;
94
+ $using_amazon_s3_storage = ((!$req['file_storage'] || strcasecmp((string)$req['file_storage'], 's3') === 0) && c_ws_plugin__s2member_utils_conds::using_amazon_s3_storage()) ? TRUE : FALSE;
95
+ $using_amazon_storage = ($using_amazon_cf_storage || $using_amazon_s3_storage) ? TRUE : FALSE;
96
+
97
+ $excluded = apply_filters('ws_plugin__s2member_check_file_download_access_excluded', FALSE, get_defined_vars());
98
+ $valid_file_download_key = ($req['file_download_key'] && is_string($req['file_download_key']) && $creating && (!isset($req['check_user']) || !filter_var($req['check_user'], FILTER_VALIDATE_BOOLEAN)) && (!isset($req['count_against_user']) || !filter_var($req['count_against_user'], FILTER_VALIDATE_BOOLEAN))) ? TRUE : FALSE;
99
+ $valid_file_download_key = (!$valid_file_download_key && $req['file_download_key'] && is_string($req['file_download_key'])) ? c_ws_plugin__s2member_files_in::check_file_download_key($req['file_download'], $req['file_download_key']) : FALSE;
100
+ $checking_user = ($excluded || $valid_file_download_key || ($creating && (!isset($req['check_user']) || !filter_var($req['check_user'], FILTER_VALIDATE_BOOLEAN)) && (!isset($req['count_against_user']) || !filter_var($req['count_against_user'], FILTER_VALIDATE_BOOLEAN)))) ? FALSE : TRUE;
101
+ $updating_user_counter = ($serving_range || !$checking_user || ($creating && (!isset($req['count_against_user']) || !filter_var($req['count_against_user'], FILTER_VALIDATE_BOOLEAN)))) ? FALSE : TRUE;
102
+
103
+ if(($serving || $creating) && $checking_user) // In either case, the following routines apply whenever we ARE ``$checking_user``.
104
{
105
+ if(!$using_amazon_storage && !file_exists($GLOBALS['WS_PLUGIN__']['s2member']['c']['files_dir'].'/'.$req['file_download']))
106
+ {
107
+ if($serving) // We only need this section when/if we're actually serving.
108
{
109
+ status_header(404);
110
+ header('Content-Type: text/html; charset=UTF-8');
111
+ while(@ob_end_clean()) ; // Clean any existing output buffers.
112
+ exit(_x('<strong>404: Sorry, file not found.</strong> Please contact Support for assistance.', 's2member-front', 's2member'));
113
}
114
+ return FALSE; // Else return false.
115
+ }
116
+ else if($req['file_download_key'] && is_string($req['file_download_key']) && !$valid_file_download_key)
117
+ {
118
+ if($serving) // We only need this section when/if we're actually serving.
119
+ {
120
+ status_header(503);
121
+ header('Content-Type: text/html; charset=UTF-8');
122
+ while(@ob_end_clean()) ; // Clean any existing output buffers.
123
+ exit(_x('<strong>503 (Invalid Key):</strong> Sorry, your access to this file has expired. Please contact Support for assistance.', 's2member-front', 's2member'));
124
+ }
125
+ return FALSE; // Else return false.
126
+ }
127
+ else // Default behavior; check file download access against the current user.
128
+ {
129
+ if($serving) // We only need remote functionality when/if we're actually serving.
130
+ if(!has_filter('ws_plugin__s2member_check_file_download_access_user', 'c_ws_plugin__s2member_files_in::check_file_remote_authorization'))
131
+ add_filter('ws_plugin__s2member_check_file_download_access_user', 'c_ws_plugin__s2member_files_in::check_file_remote_authorization', 10, 2);
132
+
133
+ if($creating) // We only need remote functionality when/if we're actually serving.
134
+ if(has_filter('ws_plugin__s2member_check_file_download_access_user', 'c_ws_plugin__s2member_files_in::check_file_remote_authorization'))
135
+ remove_filter('ws_plugin__s2member_check_file_download_access_user', 'c_ws_plugin__s2member_files_in::check_file_remote_authorization', 10, 2);
136
+
137
+ if(!$GLOBALS['WS_PLUGIN__']['s2member']['o']['membership_options_page'])
138
+ {
139
+ if($serving) // We only need this section when/if we're actually serving.
140
+ {
141
+ status_header(503);
142
+ header('Content-Type: text/html; charset=UTF-8');
143
+ while(@ob_end_clean()) ; // Clean any existing output buffers.
144
+ exit(_x('<strong>503: Basic File Downloads are NOT enabled yet.</strong> Please contact Support for assistance. If you are the site owner, please configure: <code>s2Member -› General Options -› Membership Options Page</code>.', 's2member-front', 's2member'));
145
+ }
146
+ return FALSE; // Else return false.
147
+ }
148
+ else if(($file_downloads_enabled_by_site_owner = $min_level_4_downloads = c_ws_plugin__s2member_files::min_level_4_downloads()) === FALSE)
149
+ {
150
+ if($serving) // We only need this section when/if we're actually serving.
151
+ {
152
+ status_header(503);
153
+ header('Content-Type: text/html; charset=UTF-8');
154
+ while(@ob_end_clean()) ; // Clean any existing output buffers.
155
+ exit(_x('<strong>503: Basic File Downloads are NOT enabled yet.</strong> Please contact Support for assistance. If you are the site owner, please configure: <code>s2Member -› Download Options -› Basic Download Restrictions</code>.', 's2member-front', 's2member'));
156
+ }
157
+ return FALSE; // Else return false.
158
+ }
159
+ else if(!is_object($user = apply_filters('ws_plugin__s2member_check_file_download_access_user', ((is_user_logged_in()) ? wp_get_current_user() : FALSE), get_defined_vars())) || empty($user->ID) || !($user_id = $user->ID) || !is_array($user_file_downloads = c_ws_plugin__s2member_files::user_downloads($user)) || (!$user->has_cap('administrator') && (!$user_file_downloads['allowed'] || !$user_file_downloads['allowed_days'])))
160
+ {
161
+ if(preg_match('/(?:^|\/)access[_\-]s2member[_\-]level([0-9]+)\//', $req['file_download'], $m) && strlen($req_level = $m[1]) && (!is_object($user) || empty($user->ID) || !$user->has_cap('access_s2member_level'.$req_level)))
162
+ {
163
+ if($serving) // We only need this section when/if we're actually serving.
164
+ c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars('file', $req['file_download'], 'level', $req_level, $_SERVER['REQUEST_URI']).exit();
165
166
+ return FALSE; // Else return false.
167
+ }
168
+ else if(preg_match('/(?:^|\/)access[_\-]s2member[_\-]ccap[_\-](.+?)\//', $req['file_download'], $m) && strlen($req_ccap = preg_replace('/-/', '_', $m[1])) && (!is_object($user) || empty($user->ID) || !$user->has_cap('access_s2member_ccap_'.$req_ccap)))
169
{
170
+ if($serving) // We only need this section when/if we're actually serving.
171
+ c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars('file', $req['file_download'], 'ccap', $req_ccap, $_SERVER['REQUEST_URI']).exit();
172
173
+ return FALSE; // Else return false.
174
+ }
175
+ else if($serving) // We only need this section when/if we're actually serving.
176
+ c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars('file', $req['file_download'], 'level', $min_level_4_downloads, $_SERVER['REQUEST_URI']).exit();
177
178
+ return FALSE; // Else return false.
179
+ }
180
+ else if(preg_match('/(?:^|\/)access[_\-]s2member[_\-]level([0-9]+)\//', $req['file_download'], $m) && strlen($req_level = $m[1]) && !$user->has_cap('access_s2member_level'.$req_level))
181
+ {
182
+ if($serving) // We only need this section when/if we're actually serving.
183
+ c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars('file', $req['file_download'], 'level', $req_level, $_SERVER['REQUEST_URI']).exit();
184
185
+ return FALSE; // Else return false.
186
+ }
187
+ else if(preg_match('/(?:^|\/)access[_\-]s2member[_\-]ccap[_\-](.+?)\//', $req['file_download'], $m) && strlen($req_ccap = preg_replace('/-/', '_', $m[1])) && !$user->has_cap('access_s2member_ccap_'.$req_ccap))
188
+ {
189
+ if($serving) // We only need this section when/if we're actually serving.
190
+ c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars('file', $req['file_download'], 'ccap', $req_ccap, $_SERVER['REQUEST_URI']).exit();
191
192
+ return FALSE; // Else return false.
193
+ }
194
+ else if($serving || $creating) // In either case, the following routines apply.
195
+ {
196
+ $user_previous_file_downloads = 0; // Downloads the User has already; in current period/cycle.
197
+ $user_already_downloaded_this_file = $user_already_downloaded_a_streaming_variation_of_this_file = FALSE;
198
199
+ $user_file_download_access_log = (is_array($user_file_download_access_log = get_user_option('s2member_file_download_access_log', $user_id))) ? $user_file_download_access_log : array();
200
+ $user_file_download_access_arc = (is_array($user_file_download_access_arc = get_user_option('s2member_file_download_access_arc', $user_id))) ? $user_file_download_access_arc : array();
201
202
+ $streaming_file_extns = c_ws_plugin__s2member_utils_strings::preg_quote_deep($GLOBALS['WS_PLUGIN__']['s2member']['c']['streaming_file_extns'], '/');
203
+ $streaming_variations = '/\.('.implode('|', $streaming_file_extns).')#x2F;i'; // Only count one streaming media file variation.
204
205
+ foreach($user_file_download_access_log as $user_file_download_access_log_entry_key => $user_file_download_access_log_entry)
206
+ {
207
+ if(isset($user_file_download_access_log_entry['date'], $user_file_download_access_log_entry['file'])) // Weed out corrupt/empty log entries.
208
+ {
209
+ if(strtotime($user_file_download_access_log_entry['date']) < strtotime('-'.$user_file_downloads['allowed_days'].' days'))
210
{
211
+ unset($user_file_download_access_log[$user_file_download_access_log_entry_key]); // Remove it from the `log`.
212
+ $user_file_download_access_arc[] = $user_file_download_access_log_entry; // Move `log` entry to the `archive` now.
213
}
214
+ else if(strtotime($user_file_download_access_log_entry['date']) >= strtotime('-'.$user_file_downloads['allowed_days'].' days'))
215
{
216
+ $user_previous_file_downloads++; // Previous files always count against this User/Member.
217
218
+ $_user_file_download_access_log_entry = & $user_file_download_access_log[$user_file_download_access_log_entry_key];
219
+ $_user_already_downloaded_this_file = $_user_already_downloaded_a_streaming_variation_of_this_file = FALSE;
220
221
+ if($user_file_download_access_log_entry['file'] === $req['file_download']) // Already downloaded this file? If yes, mark this flag as true.
222
+ $user_already_downloaded_this_file = $_user_already_downloaded_this_file = TRUE; // Already downloaded this file? If yes, mark as true.
223
224
+ else if(preg_replace($streaming_variations, '', $user_file_download_access_log_entry['file']) === preg_replace($streaming_variations, '', $req['file_download']))
225
+ $user_already_downloaded_this_file = $_user_already_downloaded_this_file = $user_already_downloaded_a_streaming_variation_of_this_file = $_user_already_downloaded_a_streaming_variation_of_this_file = TRUE;
226
227
+ if($updating_user_counter && ($_user_already_downloaded_this_file || $_user_already_downloaded_a_streaming_variation_of_this_file)) // Updating counter?
228
+ {
229
+ $_user_file_download_access_log_entry['ltime'] = time(); // First, we update the last download time for this file.
230
231
+ if(!empty($user_file_download_access_log_entry['counter'])) // Backward compatibility here. Is this even set?
232
+ $_user_file_download_access_log_entry['counter'] = (int)$user_file_download_access_log_entry['counter'] + 1;
233
+ else // Backward compatibility here. Default value to `1`, if this is NOT even set yet.
234
+ $_user_file_download_access_log_entry['counter'] = 1 + 1;
235
+ }
236
+ }
237
+ }
238
+ else // Weed out empty log entries. Some older versions of s2Member may have corrupt/empty log entries.
239
+ unset($user_file_download_access_log[$user_file_download_access_log_entry_key]); // Remove.
240
+ }
241
+ if($updating_user_counter && !$user_already_downloaded_this_file && !$user_already_downloaded_a_streaming_variation_of_this_file) // Do we need a new log entry for this file?
242
+ $user_file_download_access_log[] = array('date' => date('Y-m-d'), 'time' => time(), 'ltime' => time(), 'file' => $req['file_download'], 'counter' => 1);
243
244
+ if($user_previous_file_downloads >= $user_file_downloads['allowed'] && !$user_already_downloaded_this_file && !$user_already_downloaded_a_streaming_variation_of_this_file && !$user->has_cap('administrator'))
245
+ {
246
+ if($serving) // We only need this section when/if we're actually serving.
247
+ wp_redirect(add_query_arg(urlencode_deep(array('_s2member_seeking' => array('type' => 'file', 'file' => $req['file_download'], '_uri' => base64_encode($_SERVER['REQUEST_URI'])), 's2member_seeking' => 'file-'.$req['file_download'])), get_page_link($GLOBALS['WS_PLUGIN__']['s2member']['o']['file_download_limit_exceeded_page'])), apply_filters('ws_plugin__s2member_content_redirect_status', 301, get_defined_vars())).exit();
248
249
+ return FALSE; // Else return false.
250
+ }
251
+ else if($updating_user_counter) // Save/update counter? By default, we do NOT update the counter when a URL is simply being created for access.
252
+ update_user_option($user_id, 's2member_file_download_access_log', c_ws_plugin__s2member_utils_arrays::array_unique($user_file_download_access_log)).update_user_option($user_id, 's2member_file_download_access_arc', c_ws_plugin__s2member_utils_arrays::array_unique($user_file_download_access_arc));
253
+ }
254
+ }
255
+ }
256
+ else // Otherwise, we're either NOT ``$checking_user``; or permission was granted with a valid File Download Key.
257
+ {
258
+ if(!$using_amazon_storage && !file_exists($GLOBALS['WS_PLUGIN__']['s2member']['c']['files_dir'].'/'.$req['file_download']))
259
+ {
260
+ if($serving) // We only need this section when/if we're actually serving.
261
+ {
262
+ status_header(404);
263
+ header('Content-Type: text/html; charset=UTF-8');
264
+ while(@ob_end_clean()) ; // Clean any existing output buffers.
265
+ exit(_x('<strong>404: Sorry, file not found.</strong> Please contact Support for assistance.', 's2member-front', 's2member'));
266
+ }
267
+ return FALSE; // Else return false.
268
+ }
269
+ }
270
+ if($serving || $creating) // In either case, the following routines apply.
271
+ {
272
+ $basename = basename($req['file_download']);
273
+ $mimetypes = parse_ini_file(dirname(dirname(dirname(__FILE__))).'/includes/mime-types.ini');
274
+ $extension = strtolower(substr($req['file_download'], strrpos($req['file_download'], '.') + 1));
275
+
276
+ $key = ($req['file_download_key'] && is_string($req['file_download_key'])) ? $req['file_download_key'] : FALSE;
277
+
278
+ $stream = (isset($req['file_stream'])) ? filter_var($req['file_stream'], FILTER_VALIDATE_BOOLEAN) : ((in_array($extension, preg_split('/['."\r\n\t".'\s;,]+/', $GLOBALS['WS_PLUGIN__']['s2member']['o']['file_download_stream_extensions']))) ? TRUE : FALSE);
279
+ $inline = (!$stream && isset($req['file_inline'])) ? filter_var($req['file_inline'], FILTER_VALIDATE_BOOLEAN) : (($stream || in_array($extension, preg_split('/['."\r\n\t".'\s;,]+/', $GLOBALS['WS_PLUGIN__']['s2member']['o']['file_download_inline_extensions']))) ? TRUE : FALSE);
280
+ $ssl = (isset($req['file_ssl'])) ? filter_var($req['file_ssl'], FILTER_VALIDATE_BOOLEAN) : ((is_ssl()) ? TRUE : FALSE);
281
+ $storage = ($req['file_storage'] && is_string($req['file_storage'])) ? strtolower($req['file_storage']) : FALSE;
282
+ $remote = (isset($req['file_remote'])) ? filter_var($req['file_remote'], FILTER_VALIDATE_BOOLEAN) : FALSE;
283
+
284
+ $_basename_dir_app_data = c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS['WS_PLUGIN__']['s2member']['c']['files_dir']);
285
+ $rewrite_base_guess = (is_dir(dirname($GLOBALS['WS_PLUGIN__']['s2member']['c']['dir']).'/'.$_basename_dir_app_data)) ? dirname($GLOBALS['WS_PLUGIN__']['s2member']['c']['dir_url']).'/'.$_basename_dir_app_data : content_url('/'.$_basename_dir_app_data);
286
+ $rewrite_base = ($req['file_rewrite_base'] && is_string($req['file_rewrite_base'])) ? $req['file_rewrite_base'] : FALSE;
287
+ $rewrite = $rewriting = (!$rewrite_base && isset($req['file_rewrite'])) ? filter_var($req['file_rewrite'], FILTER_VALIDATE_BOOLEAN) : (($rewrite_base) ? TRUE : FALSE);
288
+ unset($_basename_dir_app_data); // A little housekeeping here.
289
+
290
+ $skip_confirmation = (isset($req['skip_confirmation'])) ? filter_var($req['skip_confirmation'], FILTER_VALIDATE_BOOLEAN) : FALSE;
291
+ $url_to_storage_source = (isset($req['url_to_storage_source'])) ? filter_var($req['url_to_storage_source'], FILTER_VALIDATE_BOOLEAN) : FALSE;
292
+
293
+ $file = $GLOBALS['WS_PLUGIN__']['s2member']['c']['files_dir'].'/'.$req['file_download'];
294
+ $pathinfo = (!$using_amazon_storage && $file) ? pathinfo($file) : array();
295
+ $mimetype = ($mimetypes[$extension]) ? $mimetypes[$extension] : 'application/octet-stream';
296
+ $disposition = (($inline) ? 'inline' : 'attachment').'; filename="'.c_ws_plugin__s2member_utils_strings::esc_dq($basename).'"; filename*=UTF-8\'\''.rawurlencode($basename);
297
+ $length = (!$using_amazon_storage && $file) ? filesize($file) : -1;
298
+
299
+ foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $__v;
300
+ do_action('ws_plugin__s2member_during_file_download_access', get_defined_vars());
301
+ unset($__refs, $__v); // Housekeeping.
302
+
303
+ if($using_amazon_storage && $using_amazon_cf_storage && ($serving || ($creating && $url_to_storage_source)))
304
+ {
305
+ if($serving) // We only need this section when/if we're actually serving.
306
+ wp_redirect(c_ws_plugin__s2member_files_in::amazon_cf_url($req['file_download'], $stream, $inline, $ssl, $basename, $mimetype)).exit();
307
+
308
+ return apply_filters('ws_plugin__s2member_file_download_access_url', c_ws_plugin__s2member_files_in::amazon_cf_url($req['file_download'], $stream, $inline, $ssl, $basename, $mimetype), get_defined_vars());
309
+ }
310
+ else if($using_amazon_storage && $using_amazon_s3_storage && ($serving || ($creating && $url_to_storage_source)))
311
+ {
312
+ if($serving) // We only need this section when/if we're actually serving.
313
+ wp_redirect(c_ws_plugin__s2member_files_in::amazon_s3_url($req['file_download'], $stream, $inline, $ssl, $basename, $mimetype)).exit();
314
+
315
+ return apply_filters('ws_plugin__s2member_file_download_access_url', c_ws_plugin__s2member_files_in::amazon_s3_url($req['file_download'], $stream, $inline, $ssl, $basename, $mimetype), get_defined_vars());
316
+ }
317
+ else if($creating && $rewriting) // Creating a rewrite URL, pointing to local storage.
318
+ { // Note: we don't URL encode unreserved chars. Improves media player compatibility.
319
+
320
+ $_url_e_key = ($key) ? c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($key)) : '';
321
+ $_url_e_storage = ($storage) ? c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($storage)) : '';
322
+ $_url_e_file = c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($req['file_download']));
323
+ $_url_e_file = str_ireplace('%2F', '/', $_url_e_file);
324
+
325
+ $url = ($rewrite_base) ? rtrim($rewrite_base, '/') : rtrim($rewrite_base_guess, '/');
326
+ $url .= (isset($req['file_download_key'])) ? (($key && $_url_e_key) ? '/s2member-file-download-key-'.$_url_e_key : '') : '';
327
+ $url .= (isset($req['file_stream'])) ? (($stream) ? '/s2member-file-stream' : '/s2member-file-stream-no') : '';
328
+ $url .= (isset($req['file_inline'])) ? (($inline) ? '/s2member-file-inline' : '/s2member-file-inline-no') : '';
329
+ $url .= (isset($req['file_storage'])) ? (($storage && $_url_e_storage) ? '/s2member-file-storage-'.$_url_e_storage : '') : '';
330
+ $url .= (isset($req['file_remote'])) ? (($remote) ? '/s2member-file-remote' : '/s2member-file-remote-no') : '';
331
+ $url .= (isset($req['skip_confirmation'])) ? (($skip_confirmation) ? '/s2member-skip-confirmation' : '/s2member-skip-confirmation-no') : '';
332
+
333
+ $url = $url.'/'.$_url_e_file; // File Download Access URL via `mod_rewrite` functionality.
334
+ $url = ($ssl) ? preg_replace('/^https?/', 'https', $url) : preg_replace('/^https?/', 'http', $url);
335
+
336
+ return apply_filters('ws_plugin__s2member_file_download_access_url', $url, get_defined_vars());
337
+ }
338
+ else if($creating) // Else we're creating a URL w/ a query-string; w/ local storage.
339
+ { // Note: we don't URL encode unreserved chars. Improves media player compatibility.
340
+
341
+ $_url_e_key = ($key) ? c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($key)) : '';
342
+ $_url_e_storage = ($storage) ? c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($storage)) : '';
343
+ $_url_e_file = c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode($req['file_download']));
344
+ $_url_e_file = str_ireplace('%2F', '/', $_url_e_file);
345
+
346
+ $url = (isset($req['file_download_key'])) ? (($key && $_url_e_key) ? '&s2member_file_download_key='.$_url_e_key : '') : '';
347
+ $url .= (isset($req['file_stream'])) ? (($stream) ? '&s2member_file_stream=yes' : '&s2member_file_stream=no') : '';
348
+ $url .= (isset($req['file_inline'])) ? (($inline) ? '&s2member_file_inline=yes' : '&s2member_file_inline=no') : '';
349
+ $url .= (isset($req['file_storage'])) ? (($storage && $_url_e_storage) ? '&s2member_file_storage='.$_url_e_storage : '') : '';
350
+ $url .= (isset($req['file_remote'])) ? (($remote) ? '&s2member_file_remote=yes' : '&s2member_file_remote=no') : '';
351
+ $url .= (isset($req['skip_confirmation'])) ? (($skip_confirmation) ? '&s2member_skip_confirmation=yes' : '&s2member_skip_confirmation=no') : '';
352
+
353
+ $url = site_url('/?'.ltrim($url.'&s2member_file_download=/'.$_url_e_file, '&'));
354
+ $url = ($ssl) ? preg_replace('/^https?/', 'https', $url) : preg_replace('/^https?/', 'http', $url);
355
+
356
+ return apply_filters('ws_plugin__s2member_file_download_access_url', $url, get_defined_vars());
357
+ }
358
+ else if($serving) // Else, ``if ($serving)``, use local storage.
359
+ {
360
+ @set_time_limit(0);
361
+
362
+ @ini_set('zlib.output_compression', 0);
363
+ if(function_exists('apache_setenv'))
364
+ @apache_setenv('no-gzip', '1');
365
+
366
+ $content_encoding_header = 'Content-Encoding:'; // Default value; standards compliant.
367
+ if($GLOBALS['WS_PLUGIN__']['s2member']['o']['file_download_content_encodong_none'])
368
+ $content_encoding_header = 'Content-Encoding: none';
369
+
370
+ while(@ob_end_clean()) ; // Cleans existing output buffers.
371
+
372
+ if($range) // Requesting a specific byte range?
373
+ {
374
+ if(strpos($range, '=') === FALSE) // Invalid range?
375
+ {
376
+ status_header(416);
377
+ nocache_headers();
378
+ header($content_encoding_header);
379
+ header('Accept-Ranges: bytes');
380
+ header('Content-Type: '.$mimetype);
381
+ header('Content-Length: '.$length);
382
+ header('Content-Disposition: '.$disposition);
383
+ exit(); // Stop here (invalid).
384
+ }
385
+ list($range_type, $byte_range) = preg_split('/\s*\=\s*/', $range, 2);
386
387
+ $range_type = strtolower(trim($range_type));
388
+ $byte_range = trim($byte_range);
389
390
+ if($range_type !== 'bytes') // Invalid range type?
391
+ {
392
+ status_header(416);
393
+ nocache_headers();
394
+ header($content_encoding_header);
395
+ header('Accept-Ranges: bytes');
396
+ header('Content-Type: '.$mimetype);
397
+ header('Content-Length: '.$length);
398
+ header('Content-Disposition: '.$disposition);
399
+ exit(); // Stop here (invalid).
400
+ }
401
+ $byte_ranges = preg_split('/\s*,\s*/', $byte_range);
402
403
+ if(strpos($byte_ranges[0], '-') === FALSE) // Invalid byte range?
404
+ {
405
+ status_header(416);
406
+ nocache_headers();
407
+ header($content_encoding_header);
408
+ header('Accept-Ranges: bytes');
409
+ header('Content-Type: '.$mimetype);
410
+ header('Content-Length: '.$length);
411
+ header('Content-Disposition: '.$disposition);
412
+ exit(); // Stop here (invalid).
413
+ }
414
+ // Only dealing with the first byte range. Others are simply ignored here.
415
+ list($byte_range_start, $byte_range_stops) = preg_split('/\s*\-\s*/', $byte_ranges[0], 2);
416
417
+ $byte_range_start = trim($byte_range_start);
418
+ $byte_range_stops = trim($byte_range_stops);
419
420
+ $byte_range_start = ($byte_range_start === '') ? NULL : (integer)$byte_range_start;
421
+ $byte_range_stops = ($byte_range_stops === '') ? NULL : (integer)$byte_range_stops;
422
423
+ if(!isset($byte_range_start) && $byte_range_stops > 0 && $byte_range_stops <= $length)
424
+ {
425
+ $byte_range_start = $length - $byte_range_stops;
426
+ $byte_range_stops = $length - 1; // The last X number of bytes.
427
}
428
+ else if(!isset($byte_range_stops) && $byte_range_start >= 0 && $byte_range_start < $length - 1)
429
+ {
430
+ $byte_range_stops = $length - 1; // To the end of the file in this case.
431
+ }
432
+ else if(isset($byte_range_start, $byte_range_stops) && $byte_range_start >= 0 && $byte_range_start < $length - 1 && $byte_range_stops > $byte_range_start && $byte_range_stops <= $length - 1)
433
+ {
434
+ // Nothing to do in this case, starts/stops already defined properly.
435
+ }
436
+ else // We have an invalid byte range.
437
+ {
438
+ status_header(416);
439
+ nocache_headers();
440
+ header($content_encoding_header);
441
+ header('Accept-Ranges: bytes');
442
+ header('Content-Type: '.$mimetype);