PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / 110912
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions v110912
260917 260913 260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 111216 111220 120213 All 189 releases
s2member / includes / classes / files-in.inc.php

files-in.inc.php in s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions 110912, at includes/classes/files-in.inc.php

291 lines 20.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 *
38 * @return null Or exits script execution after serving a File Download.
39 */
40 public static function check_file_download_access ()
41 {
42 do_action ("ws_plugin__s2member_before_file_download_access", get_defined_vars ());
43 /**/
44 if (!empty ($_GET["s2member_file_download"])) /* Ignore `..`, and `^.` files like `.htaccess`. */
45 if (strpos ($_GET["s2member_file_download"], "..") === false) /* Ignore `..` if it appears anywhere. */
46 if (strpos (basename ($_GET["s2member_file_download"]), ".") !== 0) /* Ignore any/all hidden files. */
47 {
48 @set_time_limit(0) . @ini_set ("zlib.output_compression", 0) . eval ('while (@ob_end_clean ());');
49 /**/
50 $excluded = apply_filters ("ws_plugin__s2member_check_file_download_access_excluded", false, get_defined_vars ());
51 /**/
52 if (!($using_amazon_s3_storage = 0) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"])
53 $using_amazon_s3_storage = true; /* Amazon® S3 storage has been configured! */
54 /**/
55 if (!$excluded && (empty ($_GET["s2member_file_download_key"]) || (!empty ($_GET["s2member_file_download_key"]) && !($file_download_key_is_valid = ($_GET["s2member_file_download_key"] === c_ws_plugin__s2member_files::file_download_key ($_GET["s2member_file_download"]) || $_GET["s2member_file_download_key"] === c_ws_plugin__s2member_files::file_download_key ($_GET["s2member_file_download"], "ip-forever") || $_GET["s2member_file_download_key"] === c_ws_plugin__s2member_files::file_download_key ($_GET["s2member_file_download"], "universal"))))))
56 {
57 $_GET["s2member_file_download"] = trim ($_GET["s2member_file_download"], "/"); /* Trim slashes after Key comparison. */
58 /**/
59 if (!$using_amazon_s3_storage && !file_exists ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"] . "/" . $_GET["s2member_file_download"]))
60 {
61 status_header(404) . exit (_x ("404: Sorry, file not found. Please contact Support for assistance.", "s2member-front", "s2member"));
62 }
63 /**/
64 else if (!empty ($_GET["s2member_file_download_key"]) && !$file_download_key_is_valid)
65 {
66 status_header(503) . exit (_x ("503 ( Invalid Key ): Sorry, your access to this file has expired. Please contact Support for assistance.", "s2member-front", "s2member"));
67 }
68 /**/
69 else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"] || ($file_download_access_is_allowed = $min_level_4_downloads = c_ws_plugin__s2member_files::min_level_4_downloads ()) === false)
70 {
71 if (!has_filter ("ws_plugin__s2member_check_file_download_access_user", "c_ws_plugin__s2member_files_in::_file_remote_authorization"))
72 add_filter ("ws_plugin__s2member_check_file_download_access_user", "c_ws_plugin__s2member_files_in::_file_remote_authorization", 10, 2);
73 /**/
74 if ((isset ($file_download_access_is_allowed, $min_level_4_downloads) && $file_download_access_is_allowed === false) || ($file_download_access_is_allowed = $min_level_4_downloads = c_ws_plugin__s2member_files::min_level_4_downloads ()) === false)
75 {
76 status_header(503) . exit (_x ("503: Sorry, File Downloads are NOT enabled yet. Please contact Support for assistance. If you are the site owner, please configure: `s2Member -> Download Options -> Basic Download Restrictions`.", "s2member-front", "s2member"));
77 }
78 /**/
79 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 ())) || !($user_id = $user->ID))
80 {
81 if (preg_match ("/^access[_\-]s2member[_\-]level([0-9]+)\//", $_GET["s2member_file_download"], $m))
82 {
83 $level_req = $m[1]; /* Which Level does this require? */
84 if (wp_redirect (add_query_arg (urlencode_deep (array ("s2member_seeking" => "file-" . $_GET["s2member_file_download"], "s2member_level_req" => $level_req)), get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])), apply_filters ("ws_plugin__s2member_content_redirect_status", 301, get_defined_vars ())) !== "nill")
85 exit ();
86 }
87 else if (preg_match ("/^access[_\-]s2member[_\-]ccap[_\-](.+?)\//", $_GET["s2member_file_download"], $m))
88 {
89 $ccap_req = preg_replace ("/-/", "_", $m[1]); /* Which Capability does this require? */
90 if (wp_redirect (add_query_arg (urlencode_deep (array ("s2member_seeking" => "file-" . $_GET["s2member_file_download"], "s2member_ccap_req" => $ccap_req)), get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])), apply_filters ("ws_plugin__s2member_content_redirect_status", 301, get_defined_vars ())) !== "nill")
91 exit ();
92 }
93 else if (wp_redirect (add_query_arg (urlencode_deep (array ("s2member_seeking" => "file-" . $_GET["s2member_file_download"], "s2member_level_req" => (string)$min_level_4_downloads)), get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])), apply_filters ("ws_plugin__s2member_content_redirect_status", 301, get_defined_vars ())) !== "nill")
94 exit ();
95 }
96 /**/
97 else if ((!is_array ($file_downloads = c_ws_plugin__s2member_files::user_downloads ($user)) || !$file_downloads["allowed"] || !$file_downloads["allowed_days"])/**/
98 && wp_redirect (add_query_arg (urlencode_deep (array ("s2member_seeking" => "file-" . $_GET["s2member_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 ())) !== "nill")
99 exit ();
100 /**/
101 else if (preg_match ("/^access[_\-]s2member[_\-]level([0-9]+)\//", $_GET["s2member_file_download"], $m))
102 {
103 $level_req = $m[1]; /* Which Level does this require? */
104 if (!$user->has_cap ("access_s2member_level" . $level_req) /* Does the User have access to this Level? */
105 && wp_redirect (add_query_arg (urlencode_deep (array ("s2member_seeking" => "file-" . $_GET["s2member_file_download"], "s2member_level_req" => $level_req)), get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])), apply_filters ("ws_plugin__s2member_content_redirect_status", 301, get_defined_vars ())) !== "nill")
106 exit ();
107 }
108 /**/
109 else if (preg_match ("/^access[_\-]s2member[_\-]ccap[_\-](.+?)\//", $_GET["s2member_file_download"], $m))
110 {
111 $ccap_req = preg_replace ("/-/", "_", $m[1]); /* Which Capability does this require? */
112 if (!$user->has_cap ("access_s2member_ccap_" . $ccap_req) /* Does the User have access to this Custom Capability? */
113 && wp_redirect (add_query_arg (urlencode_deep (array ("s2member_seeking" => "file-" . $_GET["s2member_file_download"], "s2member_ccap_req" => $ccap_req)), get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])), apply_filters ("ws_plugin__s2member_content_redirect_status", 301, get_defined_vars ())) !== "nill")
114 exit ();
115 }
116 /**/
117 $already_downloaded = false; /* Initialize this to a false value. */
118 $previous_file_downloads = 0; /* Here we're going to count how many downloads they've performed. */
119 $max_days_logged = c_ws_plugin__s2member_files::max_download_period (); /* Longest period/days. */
120 $file_download_access_log = (array)get_user_option ("s2member_file_download_access_log", $user_id);
121 $file_download_access_arc = (array)get_user_option ("s2member_file_download_access_arc", $user_id);
122 /**/
123 foreach ($file_download_access_log as $file_download_access_log_entry_key => $file_download_access_log_entry)
124 {
125 if (strtotime ($file_download_access_log_entry["date"]) < strtotime ("-" . $max_days_logged . " days"))
126 {
127 unset($file_download_access_log[$file_download_access_log_entry_key]);
128 $file_download_access_arc[] = $file_download_access_log_entry;
129 }
130 else if (strtotime ($file_download_access_log_entry["date"]) >= strtotime ("-" . $file_downloads["allowed_days"] . " days"))
131 {
132 $previous_file_downloads++;
133 if ($file_download_access_log_entry["file"] === $_GET["s2member_file_download"])
134 $already_downloaded = true;
135 }
136 }
137 /**/
138 if (!$already_downloaded && $previous_file_downloads >= $file_downloads["allowed"] /* They have NOT already downloaded this file, and they're over their limit. */
139 && wp_redirect (add_query_arg (urlencode_deep (array ("s2member_seeking" => "file-" . $_GET["s2member_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 ())) !== "nill")
140 exit ();
141 /**/
142 if (!$already_downloaded) /* Only add this file to the log if they have not already downloaded it. */
143 $file_download_access_log[] = array ("date" => date ("Y-m-d"), "file" => $_GET["s2member_file_download"]);
144 /**/
145 update_user_option ($user_id, "s2member_file_download_access_arc", c_ws_plugin__s2member_utils_arrays::array_unique ($file_download_access_arc));
146 update_user_option ($user_id, "s2member_file_download_access_log", c_ws_plugin__s2member_utils_arrays::array_unique ($file_download_access_log));
147 }
148 }
149 else /* Otherwise... it's either $excluded; or permission was granted with a valid Download Key. */
150 {
151 $_GET["s2member_file_download"] = trim ($_GET["s2member_file_download"], "/");
152 /**/
153 if (!$using_amazon_s3_storage && !file_exists ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"] . "/" . $_GET["s2member_file_download"]))
154 {
155 status_header(404) . exit (_x ("404: Sorry, file not found. Please contact Support for assistance.", "s2member-front", "s2member"));
156 }
157 }
158 /*
159 Here we are going to put together all of the File Download information.
160 */
161 $extension = strtolower (substr ($_GET["s2member_file_download"], strrpos ($_GET["s2member_file_download"], ".") + 1)); /* To lowercase. */
162 /**/
163 $mimetypes = parse_ini_file (dirname (dirname (dirname (__FILE__))) . "/includes/mime-types.ini"); /* Types provided by: `mime-types.ini`. */
164 $mimetype = ($mimetypes[$extension]) ? $mimetypes[$extension] : "application/octet-stream"; /* Lookup the MIME type for this file extension. */
165 /**/
166 $inline = (isset ($_GET["s2member_file_inline"])) ? filter_var ($_GET["s2member_file_inline"], FILTER_VALIDATE_BOOLEAN) : ((in_array ($extension, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_inline_extensions"]))) ? true : false);
167 /**/
168 $basename = basename ($_GET["s2member_file_download"]); /* The actual name of this File Download ( i.e. the basename ); including its file extension too. */
169 /**/
170 $pathinfo = (!$using_amazon_s3_storage) ? pathinfo (($file = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"] . "/" . $_GET["s2member_file_download"])) : array ();
171 $length = (!$using_amazon_s3_storage && $file) ? filesize ($file) : -1; /* The overall file size, in bytes. */
172 /**/
173 eval('foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;');
174 do_action ("ws_plugin__s2member_during_file_download_access", get_defined_vars ());
175 unset ($__refs, $__v); /* Unset defined __refs, __v. */
176 /**/
177 if ($using_amazon_s3_storage) /* Using Amazon® S3 storage? In this case, we use an authenticated redirection to S3 storage. */
178 {
179 $amazon_s3_file_expires = strtotime ("+" . apply_filters ("ws_plugin__s2member_amazon_s3_file_expires_time", "30 seconds", get_defined_vars ()));
180 /**/
181 $amazon_s3_file = "/" . $_GET["s2member_file_download"] . "?response-cache-control=" . urlencode (($amazon_s3_cache_control = "no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0")) . "&response-content-disposition=" . urlencode (($amazon_s3_content_disposition = (($inline) ? "inline" : "attachment") . '; filename="' . $basename . '"')) . "&response-content-type=" . urlencode (($amazon_s3_content_type = $mimetype)) . "&response-expires=" . urlencode (($amazon_s3_expires = gmdate ("D, d M Y H:i:s", strtotime ("-1 week")) . " GMT"));
182 $amazon_s3_raw_file = "/" . $_GET["s2member_file_download"] . "?response-cache-control=" . $amazon_s3_cache_control . "&response-content-disposition=" . $amazon_s3_content_disposition . "&response-content-type=" . $amazon_s3_content_type . "&response-expires=" . $amazon_s3_expires;
183 $amazon_s3_signature = base64_encode (c_ws_plugin__s2member_files_in::amazon_s3_sign ("GET\n\n\n" . $amazon_s3_file_expires . "\n" . "/" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"] . $amazon_s3_raw_file));
184 /**/
185 $amazon_s3_redirection_url = "http://" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"] . ".s3.amazonaws.com" . $amazon_s3_file;
186 if (strtolower ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"]) !== $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"])
187 $amazon_s3_redirection_url = "http://s3.amazonaws.com/" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"] . $amazon_s3_file;
188 /**/
189 $amazon_s3_redirection_url .= "&AWSAccessKeyId=" . urlencode ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"]);
190 $amazon_s3_redirection_url .= "&Expires=" . urlencode ($amazon_s3_file_expires);
191 $amazon_s3_redirection_url .= "&Signature=" . urlencode ($amazon_s3_signature);
192 /**/
193 wp_redirect($amazon_s3_redirection_url) . exit ();
194 }
195 /**/
196 else /* Else, using localized storage ( default ). */
197 {
198 status_header(200);
199 header("Accept-Ranges: none");
200 header("Content-Encoding: none");
201 header("Content-Type: " . $mimetype);
202 header("Expires: " . gmdate ("D, d M Y H:i:s", strtotime ("-1 week")) . " GMT");
203 header("Last-Modified: " . gmdate ("D, d M Y H:i:s") . " GMT");
204 header("Cache-Control: no-cache, must-revalidate, max-age=0");
205 header ("Cache-Control: post-check=0, pre-check=0", false);
206 header("Pragma: no-cache");
207 /**/
208 header('Content-Disposition: ' . (($inline) ? "inline" : "attachment") . '; filename="' . $basename . '"');
209 /**/
210 if ($length && apply_filters ("ws_plugin__s2member_stream_file_downloads", true, get_defined_vars ()) && ($stream = fopen ($file, "rb")))
211 {
212 $_stream_w_content_length = (stripos (PHP_OS, "win") === 0 && (!function_exists ("apache_get_version") || apache_get_version () === false)) ? false : true;
213 /* Windows® IIS doesn't seem to like it when both `Content-Length` and `Transfer-Encoding: chunked` are sent together. */
214 if (apply_filters ("ws_plugin__s2member_stream_file_downloads_w_content_length", $_stream_w_content_length, get_defined_vars ()))
215 header("Content-Length: " . $length);
216 /**/
217 header("Transfer-Encoding: chunked"); /* Uses `Transfer-Encoding: chunked` for simulated streaming. */
218 /**/
219 while (!feof ($stream) && ($chunk_size = strlen ($data = fread ($stream, 2097152))))
220 eval('echo dechex ($chunk_size) . "\r\n". $data . "\r\n"; @flush ();');
221 /**/
222 fclose($stream) . exit ("0\r\n\r\n");
223 }
224 else if ($length) /* Else `file_get_contents()`. */
225 {
226 header("Content-Length: " . $length) . exit (file_get_contents ($file));
227 }
228 else /* Else, we have an empty file. */
229 {
230 header("Content-Length: 0") . exit (); /* Empty file. */
231 }
232 }
233 }
234 /**/
235 do_action ("ws_plugin__s2member_after_file_download_access", get_defined_vars ());
236 }
237 /**
238 * Creates an Amazon® S3 HMAC-SHA1 signature.
239 *
240 * @package s2Member\Files
241 * @since 110524RC
242 *
243 * @param str $data Input data, to be signed by this routine.
244 * @return str An HMAC-SHA1 signature for Amazon® S3.
245 */
246 public static function amazon_s3_sign ($data = FALSE)
247 {
248 $key = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
249 $key = str_pad (((strlen ($key) > 64) ? pack ('H*', sha1 ($key)) : $key), 64, chr (0x00));
250 return pack ('H*', sha1 (($key ^ str_repeat (chr (0x5c), 64)) . pack ('H*', sha1 (($key ^ str_repeat (chr (0x36), 64)) . $data))));
251 }
252 /**
253 * A sort of callback function that handles Header Authorization for File Downloads.
254 *
255 * @package s2Member\Files
256 * @since 3.5
257 *
258 * @attaches-to: ``add_filter("ws_plugin__s2member_check_file_download_access_user");``
259 *
260 * @param obj $user Expects a WP_User object passed in by the Filter.
261 * @return obj A WP_User object, possibly obtained through Header Authorization.
262 */
263 public static function _file_remote_authorization ($user = FALSE)
264 {
265 eval('foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;');
266 do_action ("_ws_plugin__s2member_before_file_remote_authorization", get_defined_vars ());
267 unset ($__refs, $__v); /* Unset defined __refs, __v. */
268 /**/
269 if (!is_object ($user) && isset ($_GET["s2member_file_remote"]) && filter_var ($_GET["s2member_file_remote"], FILTER_VALIDATE_BOOLEAN))
270 {
271 do_action ("_ws_plugin__s2member_during_file_remote_authorization_before", get_defined_vars ());
272 /**/
273 if (empty ($_SERVER["PHP_AUTH_USER"]) || empty ($_SERVER["PHP_AUTH_PW"]) || !user_pass_ok ($_SERVER["PHP_AUTH_USER"], $_SERVER["PHP_AUTH_PW"]))
274 {
275 header('WWW-Authenticate: Basic realm="' . _x ("Members Only", "s2member-front", "s2member") . '"');
276 status_header(401); /* Unauthorized status header. */
277 exit(_x ("Access Denied", "s2member-front", "s2member"));
278 }
279 else if (is_object ($_user = new WP_User ($_SERVER["PHP_AUTH_USER"])) && $_user->ID)
280 {
281 $user = $_user; /* Now assign $user. */
282 }
283 /**/
284 do_action ("_ws_plugin__s2member_during_file_remote_authorization_after", get_defined_vars ());
285 }
286 /**/
287 return apply_filters ("_ws_plugin__s2member_file_remote_authorization", $user, get_defined_vars ());
288 }
289 }
290 }
291 ?>