PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / 120213
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions v120213
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 / utils-urls.inc.php

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

367 lines 19.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * URL utilities.
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\Utilities
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_utils_urls"))
21 {
22 /**
23 * URL utilities.
24 *
25 * @package s2Member\Utilities
26 * @since 3.5
27 */
28 class c_ws_plugin__s2member_utils_urls
29 {
30 /**
31 * Builds a WordPress® signup URL to `/wp-signup.php`.
32 *
33 * @package s2Member\Utilities
34 * @since 3.5
35 *
36 * @return str Full URL to `/wp-signup.php`.
37 */
38 public static function wp_signup_url ()
39 {
40 return apply_filters ("wp_signup_location", site_url ("/wp-signup.php"));
41 }
42 /**
43 * Builds a WordPress® registration URL to `/wp-login.php?action=register`.
44 *
45 * @package s2Member\Utilities
46 * @since 3.5
47 *
48 * @return str Full URL to `/wp-login.php?action=register`.
49 */
50 public static function wp_register_url ()
51 {
52 return apply_filters ("wp_register_location", add_query_arg ("action", urlencode ("register"), wp_login_url ()), get_defined_vars ());
53 }
54 /**
55 * Builds a BuddyPress registration URL to `/register`.
56 *
57 * @package s2Member\Utilities
58 * @since 111009
59 *
60 * @return str|bool Full URL to `/register`, if BuddyPress is installed; else false.
61 */
62 public static function bp_register_url ()
63 {
64 if ( /* If BuddyPress is installed. */c_ws_plugin__s2member_utils_conds::bp_is_installed ())
65 return site_url (((function_exists ("bp_get_signup_slug")) ? bp_get_signup_slug () . "/" : BP_REGISTER_SLUG . "/"));
66 /**/
67 return /* Default return false. */ false;
68 }
69 /**
70 * Filters content redirection status *( uses 302s for browsers )*.
71 *
72 * @package s2Member\Utilities
73 * @since 3.5
74 *
75 * @attaches-to ``add_filter("ws_plugin__s2member_content_redirect_status");``
76 *
77 * @param int|str $status A numeric redirection status code.
78 * @return int|str A numeric status redirection code, possibly modified to a value of `302`.
79 *
80 * @see http://en.wikipedia.org/wiki/Web_browser_engine
81 */
82 public static function redirect_browsers_using_302_status ($status = FALSE)
83 {
84 $engines = "msie|trident|gecko|webkit|presto|konqueror|playstation";
85 /**/
86 if ( /* Default `301` status? */(int)$status === 301 && /* Have User-Agent? */ !empty ($_SERVER["HTTP_USER_AGENT"]))
87 if (($is_browser = preg_match ("/(" . $engines . ")[\/ ]([0-9\.]+)/i", $_SERVER["HTTP_USER_AGENT"])))
88 return /* Use 302 status. */ ($status = 302);
89 /**/
90 return /* Else use existing status. */ $status;
91 }
92 /**
93 * Encodes all types of amperands to `amp;`, for use in XHTML code.
94 *
95 * Note however, this is usually NOT necessary. Just use WordPress® ``esc_html()`` or ``esc_attr()``.
96 *
97 * @package s2Member\Utilities
98 * @since 111106
99 *
100 * @param str $url_uri_query A full URL, a partial URI, or just the query string.
101 * @return str A full URL, a partial URI, or just the query string; after having been encoded by this routine.
102 */
103 public static function e_amps ($url_uri_query = FALSE)
104 {
105 return str_replace ("&", "&amp;", c_ws_plugin__s2member_utils_urls::n_amps ((string)$url_uri_query));
106 }
107 /**
108 * Normalizes amperands to `&` when working with URLs, URIs, and/or query strings.
109 *
110 * @package s2Member\Utilities
111 * @since 111106
112 *
113 * @param str $url_uri_query A full URL, a partial URI, or just the query string.
114 * @return str A full URL, a partial URI, or just the query string; after having been normalized by this routine.
115 */
116 public static function n_amps ($url_uri_query = FALSE)
117 {
118 $amps = implode ("|", array_keys /* Keys are regex patterns. */ (c_ws_plugin__s2member_utils_strings::$ampersand_entities));
119 /**/
120 return /* Normalizes amperands to `&`. */ preg_replace ("/(?:" . $amps . ")/", "&", (string)$url_uri_query);
121 }
122 /**
123 * Parses out a full valid URI, from either a full URL, or a partial URI.
124 *
125 * Uses {@link s2Member\Utilities\c_ws_plugin__s2member_utils_urls::parse_url()}.
126 *
127 * @package s2Member\Utilities
128 * @since 3.5
129 *
130 * @param str $url_uri Either a full URL, or a partial URI.
131 * @return str A valid URI, starting with `/` on success, else an empty string.
132 */
133 public static function parse_uri ($url_uri = FALSE)
134 {
135 if (is_string ($url_uri) && is_array ($parse = c_ws_plugin__s2member_utils_urls::parse_url ($url_uri)))
136 {
137 $parse["path"] = (!empty ($parse["path"])) ? ((strpos ($parse["path"], "/") === 0) ? $parse["path"] : "/" . $parse["path"]) : "/";
138 /**/
139 return (!empty ($parse["query"])) ? $parse["path"] . "?" . $parse["query"] : $parse["path"];
140 }
141 else /* Force a string return value here. */
142 return /* Empty string. */ "";
143 }
144 /**
145 * Parses a URL/URI with same args as PHP's ``parse_url()`` function.
146 *
147 * This works around issues with this PHP function in versions prior to 5.3.8.
148 *
149 * @package s2Member\Utilities
150 * @since 111017
151 *
152 * @param str $url_uri Either a full URL, or a partial URI to parse.
153 * @param bool|int $component Optional. See PHP documentation on ``parse_url()`` function.
154 * @param bool $clean_path Defaults to true. s2Member will cleanup any return array `path`.
155 * @return str|array|bool The return value from PHP's ``parse_url()`` function.
156 * However, if ``$component`` is passed, s2Member forces a string return.
157 */
158 public static function parse_url ($url_uri = FALSE, $component = FALSE, $clean_path = TRUE)
159 {
160 $component = ($component === false || $component === -1) ? -1 : $component;
161 /**/
162 if (is_string ($url_uri) && /* And, there is a query string? */ strpos ($url_uri, "?") !== false)
163 {
164 list ($_, $query) = preg_split /* Split @ query string marker. */ ("/\?/", $url_uri, 2);
165 $query = /* See: <https://bugs.php.net/bug.php?id=38143>. */ str_replace ("://", urlencode ("://"), $query);
166 $url_uri = /* Put it all back together again, after the above modifications. */ $_ . "?" . $query;
167 unset /* A little housekeeping here. Unset these vars. */ ($_, $query);
168 }
169 $parse = @parse_url /* Let PHP work its magic via ``parse_url()``. */ ($url_uri, $component);
170 /**/
171 if ($clean_path && isset ($parse["path"]) && is_string ($parse["path"]) && !empty ($parse["path"]))
172 $parse["path"] = /* Clean up the path now. */ preg_replace ("/\/+/", "/", $parse["path"]);
173 /**/
174 return ($component !== -1) ? /* Force a string return value? */ (string)$parse : $parse;
175 }
176 /**
177 * Responsible for all remote communications processed by s2Member.
178 *
179 * Uses ``wp_remote_request()`` through the `WP_Http` class.
180 *
181 * @package s2Member\Utilities
182 * @since 3.5
183 *
184 * @param str $url Full URL with possible query string parameters.
185 * @param str|array $post_vars Optional. Either a string of POST vars, or an array.
186 * @param array $args Optional. An array of additional arguments used by ``wp_remote_request()``.
187 * @param bool $return_array Optional. If true, instead of a string, we return an array with elements:
188 * `code` *(http response code)*, `message` *(http response message)*, `headers` *(an array of lowercase headers)*, `body` *(the response body string)*, `response` *(full response array)*.
189 * @return str|array|bool Requested response str|array from remote location *(see ``$return_array`` parameter )*; else (bool)`false` on failure.
190 */
191 public static function remote ($url = FALSE, $post_vars = FALSE, $args = FALSE, $return_array = FALSE)
192 {
193 if ($url && /* We MUST have a valid full URL (string) before we do anything in this routine. */ is_string ($url))
194 {
195 $args = /* Force array, and disable SSL verification. */ (!is_array ($args)) ? array (): $args;
196 $args["sslverify"] = (!isset ($args["sslverify"])) ? /* Off. */ false : $args["sslverify"];
197 /**/
198 if ((is_array ($post_vars) || is_string ($post_vars)) && !empty ($post_vars))
199 $args = array_merge ($args, array ("method" => "POST", "body" => $post_vars));
200 /**/
201 if (!empty ($args["method"]) && strcasecmp ((string)$args["method"], "DELETE") === 0)
202 /* WordPress® v3.3 and prior, does NOT support `DELETE` via cURL unfortunately. */
203 add_filter ("use_curl_transport", "__return_false", /* ID via priority. */ 111209554);
204 /**/
205 $response = /* Process remote request via ``wp_remote_request()``. */ wp_remote_request ($url, $args);
206 /**/
207 remove_filter /* Remove this Filter now. */ ("use_curl_transport", "__return_false", 111209554);
208 /**/
209 if ($return_array && !is_wp_error ($response) && is_array ($response))
210 {
211 $a = array ("code" => (int)wp_remote_retrieve_response_code ($response));
212 $a = array_merge ($a, array ("message" => wp_remote_retrieve_response_message ($response)));
213 $a = array_merge ($a, array ("headers" => wp_remote_retrieve_headers ($response)));
214 $a = array_merge ($a, array ("body" => wp_remote_retrieve_body ($response)));
215 $a = array_merge ($a, array ("response" => $response));
216 /**/
217 return /* Return array w/ ``$response`` too. */ $a;
218 }
219 else if (!is_wp_error ($response) && is_array ($response) /* Return body only. */)
220 return /* Return ``$response`` body only. */ wp_remote_retrieve_body ($response);
221 /**/
222 else /* Else this remote request has failed completely. Return false. */
223 return false; /* Remote request failed, return false. */
224 }
225 else /* Else, return false. */
226 return false;
227 }
228 /**
229 * Shortens a long URL, based on s2Member configuration.
230 *
231 * @package s2Member\Utilities
232 * @since 111002
233 *
234 * @param str $url A full/long URL to be shortened.
235 * @param str $api_sp Optional. A specific URL shortening API to use. Defaults to that which is configured in the s2Member Dashboard. Normally `tiny_url`, by default.
236 * @param bool $try_backups Defaults to true. If a failure occurs with the first API, we'll try others until we have success.
237 * @return str|bool The shortened URL on success, else false on failure.
238 */
239 public static function shorten ($url = FALSE, $api_sp = FALSE, $try_backups = TRUE)
240 {
241 $url = /* Force strings, else false. */ ($url && is_string ($url)) ? $url : false;
242 $api_sp = ($api_sp && is_string ($api_sp)) ? strtolower ($api_sp) : false;
243 /**/
244 $default_url_shortener = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_url_shortener"];
245 $default_custom_str_url_shortener = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_custom_str_url_shortener"];
246 /**/
247 $apis = /* The shortening APIs currently pre-integrated in this release of s2Member. */ array ("tiny_url", "goo_gl");
248 /**/
249 if ($url && ($api = /* If specific, use it. Otherwise, use the default shortening API. */ ($api_sp) ? $api_sp : $default_url_shortener))
250 {
251 if (!$api_sp && ($custom_url = trim (apply_filters ("ws_plugin__s2member_url_shorten", false, get_defined_vars ()))) && stripos ($custom_url, "http") === 0)
252 return /* Using whatever other shortener API you prefer, over the ones available by default with s2Member. */ ($shorter_url = $custom_url);
253 /**/
254 else if (!$api_sp && stripos ($default_custom_str_url_shortener, "http") === 0 && ($custom_url = trim (c_ws_plugin__s2member_utils_urls::remote (str_ireplace (array ("%%s2_long_url%%", "%%s2_long_url_md5%%"), array (rawurlencode ($url), urlencode (md5 ($url))), $default_custom_str_url_shortener)))) && stripos ($custom_url, "http") === 0)
255 return /* Using whatever other shortener API that a site owner prefers, over the ones available by default with s2Member. */ ($shorter_url = $custom_url);
256 /**/
257 else if ($api === "tiny_url" && ($tiny_url = trim (c_ws_plugin__s2member_utils_urls::remote ("http://tinyurl.com/api-create.php?url=" . rawurlencode ($url)))) && stripos ($tiny_url, "http") === 0)
258 return /* The default tinyURL API: <http://tinyurl.com/api-create.php?url=http://www.example.com/>. */ ($shorter_url = $tiny_url);
259 /**/
260 else if ($api === "goo_gl" && ($goo_gl = json_decode (trim (c_ws_plugin__s2member_utils_urls::remote ("https://www.googleapis.com/urlshortener/v1/url" . ((($goo_gl_key = apply_filters ("ws_plugin__s2member_url_shorten_api_goo_gl_key", false))) ? "?key=" . urlencode ($goo_gl_key) : ""), json_encode (array ("longUrl" => $url)), array ("headers" => array ("Content-Type" => "application/json")))), true)) && !empty ($goo_gl["id"]) && is_string ($goo_gl_url = $goo_gl["id"]) && stripos ($goo_gl_url, "http") === 0)
261 return /* Google® API: <http://code.google.com/apis/urlshortener/v1/getting_started.html>. */ ($shorter_url = $goo_gl_url);
262 /**/
263 else if /* Try backups? This way we can still shorten the URL with a backup. */ ($try_backups && count ($apis) > 1)
264 /**/
265 foreach /* Try other backup APIs now. */ (array_diff ($apis, array ($api)) as $backup)
266 if (($backup = c_ws_plugin__s2member_utils_urls::shorten ($url, $backup, false)))
267 return /* Success, we can return now. */ ($shorter_url = $backup);
268 }
269 return /* Default return value. */ false;
270 }
271 /**
272 * Removes all s2Member-generated signatures from a full URL, a partial URI, or just a query string.
273 *
274 * @package s2Member\Utilities
275 * @since 111106
276 *
277 * @param str $url_uri_query A full URL, a partial URI, or just the query string; to remove s2Member-generated signatures from.
278 * @param str $sig_var Optional. The name of the s2Member-generated signature variable. Defaults to `_s2member_sig`.
279 * @return str A full URL, a partial URI, or just the query string; without any s2Member-generated signatures.
280 */
281 public static function remove_s2member_sigs ($url_uri_query = FALSE, $sig_var = FALSE)
282 {
283 $url_uri_query = c_ws_plugin__s2member_utils_strings::trim ((string)$url_uri_query, false, "?&=");
284 $sig_var = ($sig_var && is_string ($sig_var)) ? $sig_var : /* Use default. */ "_s2member_sig";
285 $sigs = /* Remove all signatures. */ array_unique (array ($sig_var, "_s2member_sig"));
286 /**/
287 return trim (remove_query_arg ($sigs, $url_uri_query), "?&=");
288 }
289 /**
290 * Adds an s2Member-generated signature onto a full URL, a partial URI, or just a query string.
291 *
292 * @package s2Member\Utilities
293 * @since 111106
294 *
295 * @param str $url_uri_query A full URL, a partial URI, or just a query string; to append the s2Member-generated signature onto.
296 * @param str $sig_var Optional. The name of the s2Member-generated signature variable. Defaults to `_s2member_sig`.
297 * @return str A full URL, a partial URI, or just a query string; with an s2Member-generated signature.
298 */
299 public static function add_s2member_sig ($url_uri_query = FALSE, $sig_var = FALSE)
300 {
301 $url_uri_query = $query = c_ws_plugin__s2member_utils_strings::trim ((string)$url_uri_query, false, "?&=");
302 $sig_var = ($sig_var && is_string ($sig_var)) ? $sig_var : /* Use default. */ "_s2member_sig";
303 /**/
304 $url_uri_query = $query = c_ws_plugin__s2member_utils_urls::remove_s2member_sigs ($url_uri_query, $sig_var);
305 if ( /* Is this a full URL, or a partial URI? */preg_match ("/^(?:[a-z]+\:\/\/|\/)/i", ($url_uri_query)))
306 $query = trim (c_ws_plugin__s2member_utils_urls::parse_url ($url_uri_query, PHP_URL_QUERY), "?&=");
307 /**/
308 $key = /* Obtain the proper encryption/decryption key. */ c_ws_plugin__s2member_utils_encryption::key ();
309 /**/
310 if ($url_uri_query && is_string /* We DO allow empty query strings. So we can sign a URL without one. */ ($query))
311 {
312 wp_parse_str /* Parse the query string into an array of ``$vars``. Then sort & serialize them into a string. */ ($query, $vars);
313 $vars = c_ws_plugin__s2member_utils_arrays::remove_0b_strings (c_ws_plugin__s2member_utils_strings::trim_deep ($vars));
314 $vars = serialize (c_ws_plugin__s2member_utils_arrays::ksort_deep ($vars));
315 /**/
316 $sig = /* The s2Member-generated signature. */ ($time = time ()) . "-" . md5 ($key . $time . $vars);
317 /**/
318 $url_uri_query = add_query_arg ($sig_var, urlencode ($sig), $url_uri_query);
319 }
320 return /* Possibly with a ``$sig_var`` variable. */ $url_uri_query;
321 }
322 /**
323 * Verifies an s2Member-generated signature; in a full URL, a partial URI, or in just a query string.
324 *
325 * @package s2Member\Utilities
326 * @since 111106
327 *
328 * @param str $url_uri_query A full URL, a partial URI, or just a query string. Must have an s2Member-generated signature to validate.
329 * @param bool $check_time Optional. Defaults to false. If true, s2Member will also check if the signature has expired, based on ``$exp_secs``.
330 * @param str|int $exp_secs Optional. Defaults to (int)10. If ``$check_time`` is true, s2Member will check if the signature has expired, based on ``$exp_secs``.
331 * @param str $sig_var Optional. The name of the s2Member-generated signature variable. Defaults to `_s2member_sig`.
332 * @return bool True if the s2Member-generated signature is OK, else false.
333 */
334 public static function s2member_sig_ok ($url_uri_query = FALSE, $check_time = FALSE, $exp_secs = FALSE, $sig_var = FALSE)
335 {
336 $url_uri_query = $query = c_ws_plugin__s2member_utils_strings::trim ((string)$url_uri_query, false, "?&=");
337 if ( /* Is this a full URL, or a partial URI? */preg_match ("/^(?:[a-z]+\:\/\/|\/)/i", ($url_uri_query)))
338 $query = trim (c_ws_plugin__s2member_utils_urls::parse_url ($url_uri_query, PHP_URL_QUERY), "?&=");
339 /**/
340 $check_time = /* Are we checking time? Force a boolean value here. */ ($check_time) ? true : false;
341 $exp_secs = (is_numeric ($exp_secs)) ? (int)$exp_secs : /* Else 10 seconds by default here. */ 10;
342 $sig_var = ($sig_var && is_string ($sig_var)) ? $sig_var : /* Use default. */ "_s2member_sig";
343 /**/
344 $key = /* Obtain the proper encryption/decryption key. */ c_ws_plugin__s2member_utils_encryption::key ();
345 /**/
346 if (preg_match_all /* Does ``$query`` have an s2Member-generated signature? */ ("/" . preg_quote ($sig_var, "/") . "\=([0-9]+)-([^&$]+)/", $query, $sigs))
347 {
348 $query = /* Remove existing s2Member-generated signatures. */ c_ws_plugin__s2member_utils_urls::remove_s2member_sigs ($query, $sig_var);
349 /**/
350 wp_parse_str /* Parse the query string into an array of ``$vars``. Then sort & serialize them into a string. */ ($query, $vars);
351 $vars = c_ws_plugin__s2member_utils_arrays::remove_0b_strings (c_ws_plugin__s2member_utils_strings::trim_deep ($vars));
352 $vars = serialize (c_ws_plugin__s2member_utils_arrays::ksort_deep ($vars));
353 /**/
354 ($time = $sigs[1][($i = count ($sigs[1]) - 1)]) . ($sig = $sigs[2][$i]) . ($valid_sig = md5 ($key . $time . $vars));
355 /**/
356 if /* Checking time? This must NOT be older than ``$exp_secs`` seconds ago. */ ($check_time)
357 return ($sig === $valid_sig && $time >= strtotime ("-" . $exp_secs . " seconds"));
358 /**/
359 else /* Ignoring time? Just need to compare signatures in this case. */
360 return /* Do they match up? */ ($sig === $valid_sig);
361 }
362 else /* Return false. No ``$query``, or no ``$sigs``. */
363 return /* False, it's NOT ok. */ false;
364 }
365 }
366 }
367 ?>