PluginProbe
Property Hive / 2.3.1
Property Hive v2.3.1
2.3.1 2.3.0 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 1.4.46 1.4.47 1.4.48 1.4.49 1.4.5 1.4.50 1.4.51 1.4.52 1.4.53 1.4.54 1.4.55 1.4.56 1.4.57 1.4.58 1.4.59 1.4.6 1.4.60 1.4.61 All 261 releases
← All changes | includes/class-ph-licenses.php +176 -28 2.2.42.3.1 View file →
@@ -43,9 +43,9 @@
43 43 *
44 44 * @since 1.0.0
45 45 */
46 46 public function __clone() {
47 - _doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'propertyhive' ), '1.0.0' );
47 + _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'propertyhive' ), '1.0.0' );
48 48 }
49 49
50 50 /**
51 51 * Unserializing instances of this class is forbidden.
@@ -52,9 +52,9 @@
52 52 *
53 53 * @since 1.0.0
54 54 */
55 55 public function __wakeup() {
56 - _doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'propertyhive' ), '1.0.0' );
56 + _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'propertyhive' ), '1.0.0' );
57 57 }
58 58
59 59 /**
60 60 * Constructor for the licenses class
@@ -150,8 +150,13 @@
150 150 $product_id_and_package = PH()->license->get_pro_license_product_id_and_package();
151 151
152 152 if ( isset($product_id_and_package['success']) && $product_id_and_package['success'] === true )
153 153 {
154 + if ( ( $product_id_and_package['is_trial'] ?? null ) !== false )
155 + {
156 + return false;
157 + }
158 +
154 159 if (
155 160 isset($feature['plans']) &&
156 161 isset($product_id_and_package['package']) &&
157 162 in_array($product_id_and_package['package'], $feature['plans'])
@@ -191,8 +196,10 @@
191 196 }
192 197
193 198 private function get_data_for_license_check()
194 199 {
200 + global $wpdb;
201 +
195 202 $license_type = $this->get_license_type();
196 203
197 204 $data = array();
198 205 $data['license_key_type'] = $license_type;
@@ -209,14 +216,14 @@
209 216
210 217 $data['php_version'] = phpversion();
211 218 $data['ph_version'] = PH_VERSION;
212 219 $data['wp_version'] = get_bloginfo( 'version' );
213 - $data['server'] = isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : '';
220 + $data['server'] = isset( $_SERVER['SERVER_SOFTWARE'] ) && is_string( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '';
214 221
215 222 $data['install_date'] = get_option('propertyhive_install_timestamp', '');
216 223 if ( $data['install_date'] != '' && $data['install_date'] != 0 )
217 224 {
218 - $data['install_date'] = date("jS F Y", $data['install_date']);
225 + $data['install_date'] = gmdate("jS F Y", $data['install_date']);
219 226 }
220 227
221 228 $data['multisite'] = is_multisite();
222 229 $data['theme'] = $theme;
@@ -256,8 +263,9 @@
256 263 $data['inactive_plugins'] = $inactive_plugins_data;
257 264
258 265 $data['locale'] = get_locale();
259 266
267 + // Import info
260 268 $property_import = get_option( 'propertyhive_property_import', array() );
261 269 if ( !is_array($property_import) )
262 270 {
263 271 $property_import = array();
@@ -266,13 +274,114 @@
266 274 foreach ( $property_import as $import_id => $options )
267 275 {
268 276 if ( $options['running'] == '1' )
269 277 {
278 + if ( $options['format'] == 'xml' )
279 + {
280 + $options['format'] .= ' (' . esc_url($options['xml_url']) . ')';
281 + }
282 + elseif ( $options['format'] == 'csv' )
283 + {
284 + $options['format'] .= ' (' . esc_url($options['csv_url']) . ')';
285 + }
270 286 $formats[] = $options['format'];
271 287 }
272 288 }
273 289 $data['property_import_formats'] = $formats;
274 290
291 + // Exports
292 + $formats = array();
293 +
294 + $exports = array(
295 + 'propertyhive_realtimefeed' => array(
296 + 'label' => 'RTDF',
297 + 'field' => 'send_property_api_url',
298 + ),
299 + 'propertyhive_zooplarealtimefeed' => array(
300 + 'label' => 'Zoopla',
301 + 'field' => 'send_property_api_url',
302 + ),
303 + 'propertyhive_blmexport' => array(
304 + 'label' => 'BLM',
305 + 'field' => 'ftp_host',
306 + ),
307 + );
308 +
309 + foreach ( $exports as $option_name => $config )
310 + {
311 + $property_export = get_option( $option_name, array() );
312 +
313 + if ( ! is_array( $property_export ) ) {
314 + continue;
315 + }
316 +
317 + if ( ! isset( $property_export['portals'] ) ) {
318 + continue;
319 + }
320 +
321 + if ( ! is_array( $property_export['portals'] ) ) {
322 + continue;
323 + }
324 +
325 + $portals = isset( $property_export['portals'] ) && is_array( $property_export['portals'] )
326 + ? $property_export['portals']
327 + : array();
328 +
329 + foreach ( $portals as $portal_id => $portal )
330 + {
331 + if ( ! is_array( $portal ) ) {
332 + continue;
333 + }
334 +
335 + if ( ! is_array( $portal ) || ( $portal['mode'] ?? '' ) !== 'live' ) {
336 + continue;
337 + }
338 +
339 + $destination = $portal[ $config['field'] ] ?? '';
340 +
341 + $formats[] = sprintf(
342 + '%s (%s)',
343 + $config['label'],
344 + $destination
345 + );
346 + }
347 + }
348 +
349 + $data['property_export_formats'] = $formats;
350 +
351 + // Locrating
352 + $locrating_settings = get_option( 'propertyhive_locrating', array() );
353 + if ( !empty($locrating_settings) && isset($locrating_settings['enabled']) )
354 + {
355 + $data['locrating_enabled'] = ( $locrating_settings['enabled'] == 1 ? $locrating_settings['enabled'] : 0 );
356 + }
357 +
358 + // Search analytics
359 +
360 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Aggregate current custom-table analytics for the license report; new search events and retention change these counts independently.
361 + $counts = $wpdb->get_row(
362 + "SELECT
363 + COALESCE(
364 + SUM(searched_at >= UTC_TIMESTAMP() - INTERVAL 7 DAY),
365 + 0
366 + ) AS last_7_days,
367 + COALESCE(
368 + SUM(searched_at >= UTC_TIMESTAMP() - INTERVAL 30 DAY),
369 + 0
370 + ) AS last_30_days,
371 + COUNT(*) AS last_90_days
372 + FROM {$wpdb->prefix}ph_search_log
373 + WHERE searched_at >= UTC_TIMESTAMP() - INTERVAL 90 DAY",
374 + ARRAY_A
375 + );
376 +
377 + if ( is_array($counts) )
378 + {
379 + $data['searches_last_7_days'] = (int) ( $counts['last_7_days'] ?? 0 );
380 + $data['searches_last_30_days'] = (int) ( $counts['last_30_days'] ?? 0 );
381 + $data['searches_last_90_days'] = (int) ( $counts['last_90_days'] ?? 0 );
382 + }
383 +
275 384 // get counts
276 385 $post_types = array('office', 'property', 'contact', 'appraisal', 'viewing', 'offer', 'sale', 'tenancy', 'key_date');
277 386 foreach ( $post_types as $post_type )
278 387 {
@@ -278,13 +387,14 @@
278 387 {
279 388 $args = array(
280 389 'post_type' => $post_type,
281 390 'fields' => 'ids',
282 - 'nopaging' => TRUE,
391 + 'posts_per_page' => 1,
283 392 'post_status' => 'publish'
284 393 );
285 394 if ( $post_type == 'property' )
286 395 {
396 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- On-market state is stored in property metadata; retrieve one ID and use found_posts for the aggregate count.
287 397 $args['meta_query'] = array(
288 398 array(
289 399 'key' => '_on_market',
290 400 'value' => 'yes'
@@ -297,8 +407,44 @@
297 407 $data['post_type_count_' . $post_type] = $post_query->found_posts;
298 408
299 409 wp_reset_postdata();
300 410 }
411 +
412 + $departments = array_keys( ph_get_departments() );
413 + foreach ( $departments as $department )
414 + {
415 + $department_option = 'propertyhive_active_departments_' . str_replace( 'residential-', '', $department );
416 + if ( get_option( $department_option ) != 'yes' )
417 + {
418 + continue;
419 + }
420 +
421 + $args = array(
422 + 'post_type' => 'property',
423 + 'fields' => 'ids',
424 + 'posts_per_page' => 1,
425 + 'post_status' => 'publish',
426 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Department and on-market state use property metadata; retrieve one ID and use found_posts for the opted-in aggregate count.
427 + 'meta_query' => array(
428 + array(
429 + 'key' => '_on_market',
430 + 'value' => 'yes'
431 + ),
432 + array(
433 + 'key' => '_department',
434 + 'value' => $department
435 + )
436 + )
437 + );
438 +
439 + $post_query = new WP_Query( $args );
440 +
441 + $data['property_count_by_department_' . $department] = $post_query->found_posts;
442 +
443 + wp_reset_postdata();
444 + }
445 +
446 + $data = apply_filters( 'propertyhive_license_check_data', $data );
301 447 }
302 448
303 449 return $data;
304 450 }
@@ -316,10 +462,9 @@
316 462 }
317 463
318 464 update_option( 'propertyhive_last_license_check', time() );
319 465
320 - // Start by removing what we already know about the license
321 - update_option( 'propertyhive_license_key_details', '', 'no' );
466 + // Retain last-known license details during outages; replace them only with a valid HTTPS response.
322 467 update_option( 'propertyhive_license_key_error', '', 'no' );
323 468
324 469 $data = $this->get_data_for_license_check();
325 470
@@ -325,9 +470,9 @@
325 470
326 471 $request = wp_remote_post( 'http://license.wp-property-hive.com/check-license.php', array(
327 472 'method' => 'POST',
328 473 'timeout' => 20,
329 - 'redirection' => 5,
474 + 'redirection' => 1,
330 475 'httpversion' => '1.1',
331 476 'blocking' => true,
332 477 'body' => $data,
333 478 'user-agent' => 'PH/' . PH_VERSION . '; ' . get_bloginfo( 'url' )
@@ -334,29 +479,26 @@
334 479 ) );
335 480
336 481 if ( is_wp_error( $request ) )
337 482 {
338 - update_option( 'propertyhive_license_key_details', array(), 'no' );
339 - update_option( 'propertyhive_license_key_error', $request->get_error_message(), 'no' );
483 + update_option( 'propertyhive_license_key_error', __( 'The license service could not be reached securely. Your saved license details have been retained.', 'propertyhive' ) . ' ' . $request->get_error_message(), 'no' );
340 484 return false;
341 485 }
342 486
343 - if ( isset($request['body']) && $request['body'] == '' )
487 + if ( 200 !== wp_remote_retrieve_response_code( $request ) || '' === wp_remote_retrieve_body( $request ) )
344 488 {
345 - update_option( 'propertyhive_license_key_details', array(), 'no' );
346 - update_option( 'propertyhive_license_key_error', 'No response received when checking license', 'no' );
489 + update_option( 'propertyhive_license_key_error', __( 'The license service returned an invalid response.', 'propertyhive' ) . ' ' . wp_remote_retrieve_response_code( $request ), 'no' );
347 490 return false;
348 491 }
349 492
350 493 $body = @unserialize($request['body'], ['allowed_classes' => false]);
351 - if ( $body !== FALSE && is_array($body) && !empty($body) )
494 + if ( $body !== FALSE && is_array($body) )
352 495 {
353 496 update_option( 'propertyhive_license_key_details', $body, 'no' );
354 497 }
355 498 else
356 499 {
357 - update_option( 'propertyhive_license_key_details', array(), 'no' );
358 - update_option( 'propertyhive_license_key_error', 'Failed to process response data: ' . print_r($request['body'], true), 'no' );
500 + update_option( 'propertyhive_license_key_error', __( 'The license service returned invalid license data.', 'propertyhive' ) . ' ' . print_r($body, true), 'no' );
359 501 }
360 502 }
361 503
362 504 public function get_current_license()
@@ -401,9 +543,9 @@
401 543 $url = 'https://wp-property-hive.com/?';
402 544 $url .= 'wc-api=wc-am-api&';
403 545 $url .= 'wc_am_action=activate&';
404 546 $url .= 'instance=' . $instance_id . '&';
405 - $url .= 'object=' . parse_url( get_site_url(), PHP_URL_HOST ) . '&';
547 + $url .= 'object=' . wp_parse_url( get_site_url(), PHP_URL_HOST ) . '&';
406 548 $url .= 'product_id=' . $license['product_id'] . '&';
407 549 $url .= 'api_key=' . $license_key;
408 550
409 551 $response = wp_remote_post( $url, array(
@@ -439,9 +581,9 @@
439 581 if ( json_last_error() !== JSON_ERROR_NONE )
440 582 {
441 583 $return = array(
442 584 'success' => false,
443 - 'error' => __( 'Failed to decode response when activating license key status. Please try again', 'propertyhive' ) . ': ' . print_r( $result, true )
585 + 'error' => __( 'Failed to decode response when activating license key status. Please try again', 'propertyhive' ) . ': ' . wp_json_encode( $result )
444 586 );
445 587 return $return;
446 588 }
447 589
@@ -466,9 +608,9 @@
466 608 else
467 609 {
468 610 $return = array(
469 611 'success' => false,
470 - 'error' => __( 'Something went wrong when trying to activate license key', 'propertyhive' ) . ': ' . print_r($body, true)
612 + 'error' => __( 'Something went wrong when trying to activate license key', 'propertyhive' ) . ': ' . wp_json_encode( $body )
471 613 );
472 614 return $return;
473 615 }
474 616 }
@@ -500,9 +642,9 @@
500 642 $url = 'https://wp-property-hive.com/?';
501 643 $url .= 'wc-api=wc-am-api&';
502 644 $url .= 'wc_am_action=deactivate&';
503 645 $url .= 'instance=' . $instance_id . '&';
504 - $url .= 'object=' . parse_url( get_site_url(), PHP_URL_HOST ) . '&';
646 + $url .= 'object=' . wp_parse_url( get_site_url(), PHP_URL_HOST ) . '&';
505 647 $url .= 'product_id=' . $license['product_id'] . '&';
506 648 $url .= 'api_key=' . $license_key;
507 649
508 650 $response = wp_remote_post( $url, array(
@@ -538,9 +680,9 @@
538 680 if ( json_last_error() !== JSON_ERROR_NONE )
539 681 {
540 682 $return = array(
541 683 'success' => false,
542 - 'error' => __( 'Failed to decode response when deactivating license key status. Please try again', 'propertyhive' ) . ': ' . print_r( $result, true )
684 + 'error' => __( 'Failed to decode response when deactivating license key status. Please try again', 'propertyhive' ) . ': ' . wp_json_encode( $result )
543 685 );
544 686 return $return;
545 687 }
546 688
@@ -565,9 +707,9 @@
565 707 else
566 708 {
567 709 $return = array(
568 710 'success' => false,
569 - 'error' => __( 'Something went wrong when trying to deactivate license key', 'propertyhive' ) . ': ' . print_r($body, true)
711 + 'error' => __( 'Something went wrong when trying to deactivate license key', 'propertyhive' ) . ': ' . wp_json_encode( $body )
570 712 );
571 713 return $return;
572 714 }
573 715 }
@@ -668,9 +810,9 @@
668 810 if ( json_last_error() !== JSON_ERROR_NONE )
669 811 {
670 812 $return = array(
671 813 'success' => false,
672 - 'error' => __( 'Failed to decode response when requesting license key product list. Please try again', 'propertyhive' ) . ': ' . print_r( $result, true )
814 + 'error' => __( 'Failed to decode response when requesting license key product list. Please try again', 'propertyhive' ) . ': ' . wp_json_encode( $result )
673 815 );
674 816
675 817 $last_known = get_option('ph_pro_last_known_license_product_id_and_package', array());
676 818 if ( !empty($last_known) )
@@ -689,8 +831,9 @@
689 831 if ( isset($body['data']['product_list']['wc_subs_resources']) && !empty($body['data']['product_list']['wc_subs_resources']) )
690 832 {
691 833 $package = false;
692 834 $product_id = '';
835 + $is_trial = null;
693 836
694 837 foreach ( $body['data']['product_list']['wc_subs_resources'] as $resource )
695 838 {
696 839 if ( isset($resource['product_id']) )
@@ -703,8 +846,12 @@
703 846 {
704 847 $package = 'complete';
705 848 }
706 849 $product_id = $resource['product_id'];
850 + $is_trial = isset( $resource['is_trial'] )
851 + && is_bool( $resource['is_trial'] )
852 + ? $resource['is_trial']
853 + : null;
707 854 }
708 855 }
709 856
710 857 if ( $package !== FALSE )
@@ -711,9 +858,10 @@
711 858 {
712 859 $return = array(
713 860 'success' => true,
714 861 'package' => $package,
715 - 'product_id' => $product_id
862 + 'product_id' => $product_id,
863 + 'is_trial' => $is_trial,
716 864 );
717 865 }
718 866 else
719 867 {
@@ -726,9 +874,9 @@
726 874 else
727 875 {
728 876 $return = array(
729 877 'success' => false,
730 - 'error' => __( 'API key doesn\'t appear to belong to any orders', 'propertyhive' ) . ': ' . print_r($body, true)
878 + 'error' => __( 'API key doesn\'t appear to belong to any orders', 'propertyhive' ) . ': ' . wp_json_encode( $body )
731 879 );
732 880 }
733 881 }
734 882 else
@@ -746,9 +894,9 @@
746 894 else
747 895 {
748 896 $return = array(
749 897 'success' => false,
750 - 'error' => __( 'Something went wrong when requesting license key product list', 'propertyhive' ) . ': ' . print_r($body, true)
898 + 'error' => __( 'Something went wrong when requesting license key product list', 'propertyhive' ) . ': ' . wp_json_encode( $body )
751 899 );
752 900
753 901 $last_known = get_option('ph_pro_last_known_license_product_id_and_package', array());
754 902 if ( !empty($last_known) )
@@ -861,9 +1009,9 @@
861 1009 if ( json_last_error() !== JSON_ERROR_NONE )
862 1010 {
863 1011 $return = array(
864 1012 'success' => false,
865 - 'error' => __( 'Failed to decode response when requesting license key status. Please try again', 'propertyhive' ) . ': ' . print_r( $result, true )
1013 + 'error' => __( 'Failed to decode response when requesting license key status. Please try again', 'propertyhive' ) . ': ' . wp_json_encode( $result )
866 1014 );
867 1015
868 1016 // error for some reason. Return last known status
869 1017 $previous_license_key_status = get_option( 'propertyhive_pro_license_key_status', '' );
@@ -911,9 +1059,9 @@
911 1059 else
912 1060 {
913 1061 $return = array(
914 1062 'success' => false,
915 - 'error' => __( 'Something went wrong when requesting license key status', 'propertyhive' ) . ': ' . print_r($body, true)
1063 + 'error' => __( 'Something went wrong when requesting license key status', 'propertyhive' ) . ': ' . wp_json_encode( $body )
916 1064 );
917 1065
918 1066 // error for some reason. Return last known status
919 1067 $previous_license_key_status = get_option( 'propertyhive_pro_license_key_status', '' );