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 +196 -32 2.2.22.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(
@@ -422,9 +564,13 @@
422 564 if ( 200 !== wp_remote_retrieve_response_code( $response ) )
423 565 {
424 566 $return = array(
425 567 'success' => false,
426 - 'error' => sprintf( __( 'Received response code %s when activating license key status', 'propertyhive' ), wp_remote_retrieve_response_code( $response ) )
568 + 'error' => sprintf(
569 + /* translators: %s: HTTP header response code */
570 + __( 'Received response code %s when activating license key status', 'propertyhive' ),
571 + wp_remote_retrieve_response_code( $response )
572 + )
427 573 );
428 574 return $return;
429 575 }
430 576
@@ -435,9 +581,9 @@
435 581 if ( json_last_error() !== JSON_ERROR_NONE )
436 582 {
437 583 $return = array(
438 584 'success' => false,
439 - '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 )
440 586 );
441 587 return $return;
442 588 }
443 589
@@ -462,9 +608,9 @@
462 608 else
463 609 {
464 610 $return = array(
465 611 'success' => false,
466 - '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 )
467 613 );
468 614 return $return;
469 615 }
470 616 }
@@ -496,9 +642,9 @@
496 642 $url = 'https://wp-property-hive.com/?';
497 643 $url .= 'wc-api=wc-am-api&';
498 644 $url .= 'wc_am_action=deactivate&';
499 645 $url .= 'instance=' . $instance_id . '&';
500 - $url .= 'object=' . parse_url( get_site_url(), PHP_URL_HOST ) . '&';
646 + $url .= 'object=' . wp_parse_url( get_site_url(), PHP_URL_HOST ) . '&';
501 647 $url .= 'product_id=' . $license['product_id'] . '&';
502 648 $url .= 'api_key=' . $license_key;
503 649
504 650 $response = wp_remote_post( $url, array(
@@ -517,9 +663,13 @@
517 663 if ( 200 !== wp_remote_retrieve_response_code( $response ) )
518 664 {
519 665 $return = array(
520 666 'success' => false,
521 - 'error' => sprintf( __( 'Received response code %s when deactivating license key status', 'propertyhive' ), wp_remote_retrieve_response_code( $response ) )
667 + 'error' => sprintf(
668 + /* translators: %s: HTTP header response code */
669 + __( 'Received response code %s when deactivating license key status', 'propertyhive' ),
670 + wp_remote_retrieve_response_code( $response )
671 + )
522 672 );
523 673 return $return;
524 674 }
525 675
@@ -530,9 +680,9 @@
530 680 if ( json_last_error() !== JSON_ERROR_NONE )
531 681 {
532 682 $return = array(
533 683 'success' => false,
534 - '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 )
535 685 );
536 686 return $return;
537 687 }
538 688
@@ -557,9 +707,9 @@
557 707 else
558 708 {
559 709 $return = array(
560 710 'success' => false,
561 - '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 )
562 712 );
563 713 return $return;
564 714 }
565 715 }
@@ -635,9 +785,13 @@
635 785 if ( 200 !== wp_remote_retrieve_response_code( $response ) )
636 786 {
637 787 $return = array(
638 788 'success' => false,
639 - 'error' => sprintf( __( 'Received response code %s when requesting license key product list', 'propertyhive' ), wp_remote_retrieve_response_code( $response ) )
789 + 'error' => sprintf(
790 + /* translators: %s: HTTP header response code */
791 + __( 'Received response code %s when requesting license key product list', 'propertyhive' ),
792 + wp_remote_retrieve_response_code( $response )
793 + )
640 794 );
641 795
642 796 $last_known = get_option('ph_pro_last_known_license_product_id_and_package', array());
643 797 if ( !empty($last_known) )
@@ -656,9 +810,9 @@
656 810 if ( json_last_error() !== JSON_ERROR_NONE )
657 811 {
658 812 $return = array(
659 813 'success' => false,
660 - '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 )
661 815 );
662 816
663 817 $last_known = get_option('ph_pro_last_known_license_product_id_and_package', array());
664 818 if ( !empty($last_known) )
@@ -677,8 +831,9 @@
677 831 if ( isset($body['data']['product_list']['wc_subs_resources']) && !empty($body['data']['product_list']['wc_subs_resources']) )
678 832 {
679 833 $package = false;
680 834 $product_id = '';
835 + $is_trial = null;
681 836
682 837 foreach ( $body['data']['product_list']['wc_subs_resources'] as $resource )
683 838 {
684 839 if ( isset($resource['product_id']) )
@@ -691,8 +846,12 @@
691 846 {
692 847 $package = 'complete';
693 848 }
694 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;
695 854 }
696 855 }
697 856
698 857 if ( $package !== FALSE )
@@ -699,9 +858,10 @@
699 858 {
700 859 $return = array(
701 860 'success' => true,
702 861 'package' => $package,
703 - 'product_id' => $product_id
862 + 'product_id' => $product_id,
863 + 'is_trial' => $is_trial,
704 864 );
705 865 }
706 866 else
707 867 {
@@ -714,9 +874,9 @@
714 874 else
715 875 {
716 876 $return = array(
717 877 'success' => false,
718 - '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 )
719 879 );
720 880 }
721 881 }
722 882 else
@@ -734,9 +894,9 @@
734 894 else
735 895 {
736 896 $return = array(
737 897 'success' => false,
738 - '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 )
739 899 );
740 900
741 901 $last_known = get_option('ph_pro_last_known_license_product_id_and_package', array());
742 902 if ( !empty($last_known) )
@@ -831,9 +991,13 @@
831 991 }
832 992
833 993 $return = array(
834 994 'success' => false,
835 - 'error' => sprintf( __( 'Received response code %s when requesting license key status', 'propertyhive' ), wp_remote_retrieve_response_code( $response ) )
995 + 'error' => sprintf(
996 + /* translators: %s: HTTP header response code */
997 + __( 'Received response code %s when requesting license key status', 'propertyhive' ),
998 + wp_remote_retrieve_response_code( $response )
999 + )
836 1000 );
837 1001
838 1002 return $return;
839 1003 }
@@ -845,9 +1009,9 @@
845 1009 if ( json_last_error() !== JSON_ERROR_NONE )
846 1010 {
847 1011 $return = array(
848 1012 'success' => false,
849 - '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 )
850 1014 );
851 1015
852 1016 // error for some reason. Return last known status
853 1017 $previous_license_key_status = get_option( 'propertyhive_pro_license_key_status', '' );
@@ -895,9 +1059,9 @@
895 1059 else
896 1060 {
897 1061 $return = array(
898 1062 'success' => false,
899 - '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 )
900 1064 );
901 1065
902 1066 // error for some reason. Return last known status
903 1067 $previous_license_key_status = get_option( 'propertyhive_pro_license_key_status', '' );