Admin
1 week ago
AssetManager
1 week ago
Category
2 years ago
Form
6 months ago
MediaLibrary
4 days ago
Package
4 days ago
User
4 days ago
Widgets
2 years ago
__
4 days ago
wpdm-core.php
5 months ago
wpdm-functions.php
4 days ago
wpdm-start-download.php
4 months ago
wpdm-strings.php
3 years ago
wpdm-core.php
363 lines
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * Warning!!! |
| 5 | * Don't change any function from here |
| 6 | * |
| 7 | */ |
| 8 | |
| 9 | use WPDM\__\Messages; |
| 10 | |
| 11 | global $stabs, $package, $wpdm_package; |
| 12 | |
| 13 | |
| 14 | function WPDM($global = null){ |
| 15 | if($global){ |
| 16 | global $$global; |
| 17 | return $$global; |
| 18 | } |
| 19 | global $WPDM; |
| 20 | return $WPDM; |
| 21 | } |
| 22 | |
| 23 | /** |
| 24 | * @param $tablink |
| 25 | * @param $newtab |
| 26 | * @param $func |
| 27 | * @deprecated Deprecated from v4.2, use filter hook 'add_wpdm_settings_tab' |
| 28 | * @usage Deprecated: From v4.2, use filter hook 'add_wpdm_settings_tab' |
| 29 | */ |
| 30 | function add_wdm_settings_tab($tablink, $newtab, $func) |
| 31 | { |
| 32 | global $stabs; |
| 33 | $stabs["{$tablink}"] = array('id' => $tablink, 'icon' => 'fa fa-cog', 'link' => 'edit.php?post_type=wpdmpro&page=settings&tab=' . $tablink, 'title' => $newtab, 'callback' => $func); |
| 34 | } |
| 35 | |
| 36 | /** |
| 37 | * @param $tabid |
| 38 | * @param $tabtitle |
| 39 | * @param $callback |
| 40 | * @param string $icon |
| 41 | * @return array |
| 42 | */ |
| 43 | function wpdm_create_settings_tab($tabid, $tabtitle, $callback, $icon = 'fa fa-cog') |
| 44 | { |
| 45 | return \WPDM\Admin\Menu\Settings::createMenu($tabid, $tabtitle, $callback, $icon); |
| 46 | } |
| 47 | |
| 48 | |
| 49 | /** |
| 50 | * @usage Check user's download limit |
| 51 | * @param $id |
| 52 | * @return bool |
| 53 | */ |
| 54 | function wpdm_is_download_limit_exceed($id) |
| 55 | { |
| 56 | return WPDM()->package->userDownloadLimitExceeded($id); |
| 57 | } |
| 58 | |
| 59 | |
| 60 | /** |
| 61 | * @param (int|array) $package Package ID (INT) or Complete Package Data (Array) |
| 62 | * @param string $ext |
| 63 | * @return string|void |
| 64 | */ |
| 65 | function wpdm_download_url($package, $params = array()) |
| 66 | { |
| 67 | if (!is_array($package)) $package = intval($package); |
| 68 | $id = is_int($package) ? $package : $package['ID']; |
| 69 | return WPDM()->package->getDownloadURL($id, $params); |
| 70 | } |
| 71 | |
| 72 | |
| 73 | /** |
| 74 | * @usage Check if a download manager category has child |
| 75 | * @param $parent |
| 76 | * @return bool |
| 77 | */ |
| 78 | |
| 79 | function wpdm_cat_has_child($parent) |
| 80 | { |
| 81 | $termchildren = get_term_children($parent, 'wpdmcategory'); |
| 82 | if (count($termchildren) > 0) return count($termchildren); |
| 83 | return false; |
| 84 | } |
| 85 | |
| 86 | /** |
| 87 | * @usage Get category checkbox list |
| 88 | * @param int $parent |
| 89 | * @param int $level |
| 90 | * @param array $sel |
| 91 | */ |
| 92 | function wpdm_cblist_categories($parent = 0, $level = 0, $sel = array()) |
| 93 | { |
| 94 | $cats = get_terms('wpdmcategory', array('hide_empty' => false, 'parent' => $parent)); |
| 95 | if (!$cats) $cats = array(); |
| 96 | if ($parent != '') echo "<ul>"; |
| 97 | foreach ($cats as $cat) { |
| 98 | $id = $cat->slug; |
| 99 | $pres = $level * 5; |
| 100 | |
| 101 | if (in_array($id, $sel)) |
| 102 | $checked = 'checked=checked'; |
| 103 | else |
| 104 | $checked = ''; |
| 105 | echo "<li style='margin-left:{$pres}px;padding-left:0'><label><input id='c$id' type='checkbox' name='file[category][]' value='$id' $checked /> " . $cat->name . "</label></li>\n"; |
| 106 | wpdm_cblist_categories($cat->term_id, $level + 1, $sel); |
| 107 | |
| 108 | } |
| 109 | if ($parent != '') echo "</ul>"; |
| 110 | } |
| 111 | |
| 112 | /** |
| 113 | * @usage Get category dropdown list |
| 114 | * @param string $name |
| 115 | * @param string $selected |
| 116 | * @param string $id |
| 117 | * @param int $echo |
| 118 | * @return string |
| 119 | */ |
| 120 | function wpdm_dropdown_categories($name = '', $selected = '', $id = '', $echo = 1) |
| 121 | { |
| 122 | return wp_dropdown_categories(array('show_option_none' => __( "Select category" , "download-manager" ), 'hierarchical' => 1, 'show_count' => 0, 'orderby' => 'name', 'echo' => $echo, 'class' => 'form-control selectpicker', 'taxonomy' => 'wpdmcategory', 'hide_empty' => 0, 'name' => $name, 'id' => $id, 'selected' => $selected)); |
| 123 | |
| 124 | } |
| 125 | |
| 126 | |
| 127 | /** |
| 128 | * @usage Post with cURL |
| 129 | * @param $url |
| 130 | * @param $data (array) |
| 131 | * @param $headers (array) |
| 132 | * @return bool|mixed|string |
| 133 | */ |
| 134 | function wpdm_remote_post($url, $data, $headers = []) |
| 135 | { |
| 136 | |
| 137 | $response = wp_remote_post($url, array( |
| 138 | 'method' => 'POST', |
| 139 | 'sslverify' => false, |
| 140 | 'timeout' => 5, |
| 141 | 'redirection' => 5, |
| 142 | 'httpversion' => '1.0', |
| 143 | 'blocking' => true, |
| 144 | 'headers' => $headers, |
| 145 | 'body' => $data, |
| 146 | 'cookies' => array() |
| 147 | ) |
| 148 | ); |
| 149 | $body = wp_remote_retrieve_body($response); |
| 150 | return $body; |
| 151 | } |
| 152 | |
| 153 | /** |
| 154 | * Verify reCAPTCHA Enterprise token |
| 155 | * @param string $token The reCAPTCHA token from the frontend |
| 156 | * @param string $expected_action Optional expected action name |
| 157 | * @return array ['success' => bool, 'score' => float, 'error' => string] |
| 158 | */ |
| 159 | function wpdm_recaptcha_enterprise_verify($token, $expected_action = '') |
| 160 | { |
| 161 | $project_id = get_option('_wpdm_recaptcha_project_id', ''); |
| 162 | $api_key = get_option('_wpdm_recaptcha_secret_key', ''); |
| 163 | $site_key = get_option('_wpdm_recaptcha_site_key', ''); |
| 164 | |
| 165 | if (empty($project_id) || empty($api_key) || empty($site_key)) { |
| 166 | return ['success' => false, 'score' => 0, 'error' => 'reCAPTCHA Enterprise not configured']; |
| 167 | } |
| 168 | |
| 169 | $url = 'https://recaptchaenterprise.googleapis.com/v1/projects/' . $project_id . '/assessments?key=' . $api_key; |
| 170 | |
| 171 | $body = [ |
| 172 | 'event' => [ |
| 173 | 'token' => $token, |
| 174 | 'siteKey' => $site_key, |
| 175 | ] |
| 176 | ]; |
| 177 | |
| 178 | if (!empty($expected_action)) { |
| 179 | $body['event']['expectedAction'] = $expected_action; |
| 180 | } |
| 181 | |
| 182 | $response = wp_remote_post($url, [ |
| 183 | 'method' => 'POST', |
| 184 | 'timeout' => 10, |
| 185 | 'headers' => ['Content-Type' => 'application/json'], |
| 186 | 'body' => wp_json_encode($body), |
| 187 | ]); |
| 188 | |
| 189 | if (is_wp_error($response)) { |
| 190 | return ['success' => false, 'score' => 0, 'error' => $response->get_error_message(), 'error_code' => 'WP_ERROR']; |
| 191 | } |
| 192 | |
| 193 | $response_code = wp_remote_retrieve_response_code($response); |
| 194 | $result = json_decode(wp_remote_retrieve_body($response), true); |
| 195 | |
| 196 | // Handle API-level errors (wrong API key, project ID, etc.) |
| 197 | if ($response_code !== 200) { |
| 198 | $api_error = isset($result['error']['message']) ? $result['error']['message'] : 'API request failed'; |
| 199 | $api_status = isset($result['error']['status']) ? $result['error']['status'] : ''; |
| 200 | return [ |
| 201 | 'success' => false, |
| 202 | 'score' => 0, |
| 203 | 'error' => $api_error, |
| 204 | 'error_code' => $api_status, |
| 205 | 'error_details' => wpdm_recaptcha_get_api_error_help($api_status, $api_error) |
| 206 | ]; |
| 207 | } |
| 208 | |
| 209 | if (!$result) { |
| 210 | return ['success' => false, 'score' => 0, 'error' => 'Invalid response from reCAPTCHA Enterprise', 'error_code' => 'INVALID_RESPONSE']; |
| 211 | } |
| 212 | |
| 213 | // Check if token is valid |
| 214 | $valid = isset($result['tokenProperties']['valid']) && $result['tokenProperties']['valid'] === true; |
| 215 | $score = isset($result['riskAnalysis']['score']) ? (float)$result['riskAnalysis']['score'] : 0; |
| 216 | $invalid_reason = isset($result['tokenProperties']['invalidReason']) ? $result['tokenProperties']['invalidReason'] : ''; |
| 217 | |
| 218 | // For checkbox mode, we mainly check validity |
| 219 | // Score threshold can be configured if needed |
| 220 | return [ |
| 221 | 'success' => $valid, |
| 222 | 'score' => $score, |
| 223 | 'error' => $valid ? '' : wpdm_recaptcha_get_error_message($invalid_reason), |
| 224 | 'error_code' => $invalid_reason, |
| 225 | 'error_details' => $valid ? '' : wpdm_recaptcha_get_error_help($invalid_reason) |
| 226 | ]; |
| 227 | } |
| 228 | |
| 229 | /** |
| 230 | * Get human-readable error message for reCAPTCHA invalid reasons |
| 231 | */ |
| 232 | function wpdm_recaptcha_get_error_message($reason) |
| 233 | { |
| 234 | $messages = [ |
| 235 | 'INVALID_REASON_UNSPECIFIED' => 'Token validation failed', |
| 236 | 'UNKNOWN_INVALID_REASON' => 'Unknown validation error', |
| 237 | 'MALFORMED' => 'Malformed token', |
| 238 | 'EXPIRED' => 'Token has expired', |
| 239 | 'DUPE' => 'Token already used', |
| 240 | 'MISSING' => 'Token is missing', |
| 241 | 'BROWSER_ERROR' => 'Browser error during verification', |
| 242 | 'SITE_MISMATCH' => 'Site key mismatch', |
| 243 | ]; |
| 244 | |
| 245 | return isset($messages[$reason]) ? $messages[$reason] : 'Verification failed'; |
| 246 | } |
| 247 | |
| 248 | /** |
| 249 | * Get troubleshooting help for reCAPTCHA errors |
| 250 | */ |
| 251 | function wpdm_recaptcha_get_error_help($reason) |
| 252 | { |
| 253 | $help = [ |
| 254 | 'INVALID_REASON_UNSPECIFIED' => 'This usually means the Site Key doesn\'t match the one registered in Google Cloud Console. Please verify: 1) The Site Key is correct, 2) Your domain is added to the allowed domains in reCAPTCHA settings, 3) The key type is "Checkbox" (not Score-based).', |
| 255 | 'UNKNOWN_INVALID_REASON' => 'An unexpected error occurred. Please try again or check Google Cloud Console for any issues.', |
| 256 | 'MALFORMED' => 'The reCAPTCHA token is corrupted. This may be caused by JavaScript conflicts. Try disabling other plugins temporarily.', |
| 257 | 'EXPIRED' => 'The CAPTCHA expired before verification. Please complete the CAPTCHA and submit quickly (within 2 minutes).', |
| 258 | 'DUPE' => 'This token was already verified. Each CAPTCHA completion can only be used once. Please complete the CAPTCHA again.', |
| 259 | 'MISSING' => 'No token was received. Ensure the reCAPTCHA widget loaded correctly and the form includes the token.', |
| 260 | 'BROWSER_ERROR' => 'The browser encountered an error. Try a different browser or check for JavaScript errors in the console.', |
| 261 | 'SITE_MISMATCH' => 'The Site Key used on this page doesn\'t match the key configured in Google Cloud. Verify your Site Key is correct.', |
| 262 | ]; |
| 263 | |
| 264 | return isset($help[$reason]) ? $help[$reason] : 'Please verify your reCAPTCHA Enterprise configuration in Google Cloud Console.'; |
| 265 | } |
| 266 | |
| 267 | /** |
| 268 | * Get troubleshooting help for API-level errors |
| 269 | */ |
| 270 | function wpdm_recaptcha_get_api_error_help($status, $message) |
| 271 | { |
| 272 | $help = [ |
| 273 | 'PERMISSION_DENIED' => 'The API Key doesn\'t have permission. Common causes: 1) API Key has HTTP referrer restrictions - this will NOT work because verification happens server-side. Remove referrer restrictions or use IP address restrictions instead (your server IP). 2) reCAPTCHA Enterprise API is not enabled in your Google Cloud project. 3) The API Key is incorrect.', |
| 274 | 'INVALID_ARGUMENT' => 'Invalid configuration. Check that your Project ID and Site Key are correct and match your Google Cloud Console settings.', |
| 275 | 'NOT_FOUND' => 'Project or resource not found. Verify your Google Cloud Project ID is correct.', |
| 276 | 'UNAUTHENTICATED' => 'Authentication failed. Your API Key may be invalid or expired. Generate a new API Key in Google Cloud Console.', |
| 277 | ]; |
| 278 | |
| 279 | if (isset($help[$status])) { |
| 280 | return $help[$status]; |
| 281 | } |
| 282 | |
| 283 | if (strpos($message, 'API key not valid') !== false) { |
| 284 | return 'Your API Key is invalid. Please check: 1) The API Key is copied correctly (no extra spaces), 2) The key hasn\'t been deleted or regenerated, 3) If the key has restrictions, do NOT use HTTP referrer restrictions - use IP address (server IP) instead, as verification is done server-side.'; |
| 285 | } |
| 286 | |
| 287 | if (strpos($message, 'Requests from referer') !== false || strpos($message, 'referer') !== false) { |
| 288 | return 'Your API Key has HTTP referrer restrictions which will not work. reCAPTCHA verification happens on the server, not in the browser, so referrer headers are not sent. Solution: In Google Cloud Console, edit your API Key and either remove all restrictions, or change to IP address restrictions using your server\'s IP address.'; |
| 289 | } |
| 290 | |
| 291 | return 'Please verify all credentials in Google Cloud Console: Project ID, Site Key, and API Key. Important: If your API Key has restrictions, do not use HTTP referrer restrictions - use IP address restrictions instead.'; |
| 292 | } |
| 293 | |
| 294 | /** |
| 295 | * @usage Get with cURL |
| 296 | * @param $url |
| 297 | * @param $headers (array) |
| 298 | * @return bool|mixed|string |
| 299 | */ |
| 300 | function wpdm_remote_get($url, $headers = []) |
| 301 | { |
| 302 | $content = ""; |
| 303 | $response = wp_remote_get($url, array('timeout' => 5, 'sslverify' => false, 'headers' => $headers)); |
| 304 | if (is_array($response)) { |
| 305 | $content = $response['body']; |
| 306 | } else |
| 307 | $content = Messages::error($response->get_error_message(), -1); |
| 308 | return $content; |
| 309 | } |
| 310 | |
| 311 | |
| 312 | function wpdm_plugin_data($dir) |
| 313 | { |
| 314 | $plugins = get_plugins(); |
| 315 | foreach ($plugins as $plugin => $data) { |
| 316 | $data['plugin_index_file'] = $plugin; |
| 317 | $plugin = explode("/", $plugin); |
| 318 | if ($plugin[0] == $dir) return $data; |
| 319 | } |
| 320 | return false; |
| 321 | } |
| 322 | |
| 323 | function wpdm_access_token(){ |
| 324 | return get_option("__wpdm_access_token", false); |
| 325 | } |
| 326 | |
| 327 | |
| 328 | function wpdm_plugin_update_email($plugin_name, $version, $update_url) |
| 329 | { |
| 330 | |
| 331 | $admin_email = get_option('admin_email'); |
| 332 | $hash = "__wpdm_" . md5($plugin_name . $version); |
| 333 | $sent = get_option($hash, false); |
| 334 | if (!$sent) { |
| 335 | |
| 336 | $message = 'New version available. Please update your copy.<br/><table class="email" style="width: 100%" cellpadding="5px"><tr><th>Plugin Name</th><th>Version</th></tr><tr><td>' . $plugin_name . '</td><td>' . $version . '</td></tr></table><div style="padding-top: 10px;"><a style="display: block;text-align: center" class="button" href="' . $update_url . '">Update Now</a></div>'; |
| 337 | |
| 338 | $params = array( |
| 339 | 'subject' => sprintf(__("[%s] Update Available"), $plugin_name, 'download-manager'), |
| 340 | 'to_email' => get_option('admin_email'), |
| 341 | 'from_name' => 'WordPress Download Manager', |
| 342 | 'from_email' => 'support@wpdownloadmanager.com', |
| 343 | 'message' => $message |
| 344 | ); |
| 345 | |
| 346 | \WPDM\__\Email::send("default", $params); |
| 347 | update_option($hash, 1, false); |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | function wpdmpro_required(){ |
| 352 | ?> |
| 353 | <div class="panel panel-default" style="position: relative;z-index: 99999999"> |
| 354 | <div class="panel-body"> |
| 355 | <div class="media"> |
| 356 | <div class="pull-right"><a href="https://www.wpdownloadmanager.com/pricing/" target="_blank" class="btn btn-primary btn-sm">Get WPDM Pro</a></div> |
| 357 | <div class="media-body lead" style="line-height: 25px">This option is only available with the WordPress Download Manager Pro!</div> |
| 358 | </div> |
| 359 | </div> |
| 360 | </div> |
| 361 | <?php |
| 362 | } |
| 363 |