Test Failed
Pull Request — master (#462)
by Kiran
18:14
created

GeoDir_Privacy::__construct()   C

Complexity

Conditions 8
Paths 32

Size

Total Lines 41
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 19
nc 32
nop 0
dl 0
loc 41
rs 5.3846
c 0
b 0
f 0
1
<?php
2
/**
3
 * Privacy/GDPR related functionality which ties into WordPress functionality.
4
 *
5
 * @since 1.6.26
6
 * @package GeoDirectory
7
 */
8
9
defined( 'ABSPATH' ) || exit;
10
11
/**
12
 * GeoDir_Privacy Class.
13
 */
14
class GeoDir_Privacy extends GeoDir_Abstract_Privacy {
15
16
	/**
17
	 * Init - hook into events.
18
	 */
19
	public function __construct() {
20
		parent::__construct( __( 'GeoDirectory', 'geodirectory' ) );
21
22
		// Include supporting classes.
23
		include_once( 'class-geodir-privacy-erasers.php' );
24
		include_once( 'class-geodir-privacy-exporters.php' );
25
26
		$gd_post_types = geodir_get_posttypes( 'object' );
27
28
		if ( ! empty( $gd_post_types ) ) {
29
			foreach ( $gd_post_types as $post_type => $info ) {
0 ignored issues
show
Bug introduced by
The expression $gd_post_types of type array|object|string is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
30
				$name = $info->labels->name;
31
32
				if ( self::allow_export_post_type_data( $post_type ) ) {
33
					// This hook registers GeoDirectory data exporters.
34
					$this->add_exporter( 'geodirectory-post-' . $post_type, wp_sprintf( __( 'User %s', 'geodirectory' ), $name ), array( 'GeoDir_Privacy_Exporters', 'post_data_exporter' ) );
0 ignored issues
show
Documentation introduced by
array('GeoDir_Privacy_Ex..., 'post_data_exporter') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
35
				}
36
			}
37
		}
38
39
		// Handles custom anonomization types not included in core.
40
		add_filter( 'wp_privacy_anonymize_data', array( $this, 'anonymize_custom_data_types' ), 10, 3 );
41
42
		if ( self::allow_export_reviews_data() ) {
43
			// Review data export
44
			add_filter( 'wp_privacy_personal_data_export_page', array( 'GeoDir_Privacy_Exporters', 'review_data_exporter' ), 10, 7 );
45
		}
46
47
		if ( self::allow_erase_reviews_data() ) {
48
			// Review data erase
49
			$this->add_eraser( 'geodirectory-post-reviews', __( 'User Listing Reviews', 'geodirectory' ), array( 'GeoDir_Privacy_Erasers', 'review_data_eraser' ) );
0 ignored issues
show
Documentation introduced by
array('GeoDir_Privacy_Er..., 'review_data_eraser') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
50
		}
51
52
		// Post favorites
53
		if ( self::allow_export_favorites_data() ) {
54
			$this->add_exporter( 'geodirectory-post-favorites', __( 'GeoDirectory Favorite Listings', 'geodirectory' ), array( 'GeoDir_Privacy_Exporters', 'favorites_data_exporter' ) );
0 ignored issues
show
Documentation introduced by
array('GeoDir_Privacy_Ex...vorites_data_exporter') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
55
		}
56
		if ( self::allow_erase_favorites_data() ) {
57
			$this->add_eraser( 'geodirectory-post-favorites', __( 'GeoDirectory Favorite Listings', 'geodirectory' ), array( 'GeoDir_Privacy_Erasers', 'favorites_data_eraser' ) );
0 ignored issues
show
Documentation introduced by
array('GeoDir_Privacy_Er...favorites_data_eraser') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
58
		}
59
	}
60
61
	/**
62
	 * Add privacy policy content for the privacy policy page.
63
	 *
64
	 * @since 1.6.26
65
	 *
66
	 * @return string The default policy content.
67
	 */
68
	public function get_privacy_message() {
69
70
		$content = '<h2>' . __( 'Listings', 'geodirectory' ) . '</h2>' .
71
		           '<p>' . __( 'We collect information about you during the add listing process on our site. This information may include, but is not limited to, your name, email address, phone number, address, locations details including GPS co-ordinates and any other details that might be requested from you for the purpose of adding your business/personal listings.', 'geodirectory' ) . '</p>' .
72
		           '<p>' . __( 'Handling this data also allows us to:', 'geodirectory' ) . '</p>' .
73
		           '<ul>' .
74
		           '<li>' . __( '- Display this information in a public facing manner (such as a web page or API request) and allow website users to search and view submitted listing information.', 'geodirectory' ) . '</li>' .
75
		           '<li>' . __( '- Send you important account/order/service information.', 'geodirectory' ) . '</li>' .
76
		           '<li>' . __( '- Provide a way for users to contact your listing via the provided contact information.', 'geodirectory' ) . '</li>' .
77
		           '<li>' . __( '- Notify you of user interactions such as but not limited to review and contact notifications.', 'geodirectory' ) . '</li>' .
78
		           '<li>' . __( '- Respond to your queries or complaints.', 'geodirectory' ) . '</li>' .
79
		           '<li>' . __( '- Set up and administer your account, provide technical and/or customer support, and to verify your identity. We do this on the basis of our legitimate business interests.', 'geodirectory' ) . '</li>' .
80
		           '</ul>' .
81
		           '<h2>' . __( 'Reviews', 'geodirectory' ) . '</h2>' .
82
		           '<p>' . __( 'We collect information about you during the leave a review process on our site. This information may include, but is not limited to, your name, email address, IP address, website url, image(s), review ratings and review texts.', 'geodirectory' ) . '</p>' .
83
		           '<p>' . __( 'Handling this data also allows us to:', 'geodirectory' ) . '</p>' .
84
		           '<ul>' .
85
		           '<li>' . __( '- Display this information in a public facing manner (such as a web page or API request).', 'geodirectory' ) . '</li>' .
86
		           '<li>' . __( '- Notify you of interactions such as approval or rejection of your review.', 'geodirectory' ) . '</li>' .
87
		           '<li>' . __( '- Notify you of user interactions such as reply notifications.', 'geodirectory' ) . '</li>' .
88
		           '</ul>' .
89
		           '<h2>' . __( 'Listing contact forms', 'geodirectory' ) . '</h2>' .
90
		           '<p>' . __( 'We may collect information about you when you submit a contact form to a listing. This information may include, but is not limited to, your name, email address, IP address and contact texts.', 'geodirectory' ) . '</p>' .
91
		           '<p>' . __( 'Handling this data also allows us to:', 'geodirectory' ) . '</p>' .
92
		           '<ul>' .
93
		           '<li>' . __( '- Send your contact message and details to the listings contact email.', 'geodirectory' ) . '</li>' .
94
		           '<li>' . __( '- Monitor the contact system for spam and abuse.', 'geodirectory' ) . '</li>' .
95
		           '</ul>';
96
97
98
		return apply_filters( 'geodir_privacy_policy_content', $content) ;
99
	}
100
101
	/**
102
	 * Handle some custom types of data and anonymize them.
103
	 *
104
	 * @param string $anonymous Anonymized string.
105
	 * @param string $type Type of data.
106
	 * @param string $data The data being anonymized.
107
	 * @return string Anonymized string.
108
	 */
109
	public function anonymize_custom_data_types( $anonymous, $type, $data ) {
110
		switch ( $type ) {
111
			case 'phone':
112
				$anonymous = preg_replace( '/\d/u', '0', $data );
113
				break;
114
			case 'numeric_id':
115
				$anonymous = 0;
116
				break;
117
			case 'gps':
118
				$anonymous = '0';
119
				break;
120
		}
121
		return $anonymous;
122
	}
123
124
	public static function personal_data_exporter_key() {
125
		if ( ! wp_doing_ajax() ) {
126
			return false;
127
		}
128
129
		if ( empty( $_POST['id'] ) ) {
130
			return false;
131
		}
132
		$request_id = (int) $_POST['id'];
133
134
		if ( $request_id < 1 ) {
135
			return false;
136
		}
137
138
		if ( ! current_user_can( 'export_others_personal_data' ) ) {
139
			return false;
140
		}
141
142
		// Get the request data.
143
		$request = wp_get_user_request_data( $request_id );
144
145
		if ( ! $request || 'export_personal_data' !== $request->action_name ) {
146
			return false;
147
		}
148
149
		$email_address = $request->email;
150
		if ( ! is_email( $email_address ) ) {
151
			return false;
152
		}
153
154
		if ( ! isset( $_POST['exporter'] ) ) {
155
			return false;
156
		}
157
		$exporter_index = (int) $_POST['exporter'];
158
159
		if ( ! isset( $_POST['page'] ) ) {
160
			return false;
161
		}
162
		$page = (int) $_POST['page'];
163
164
		$send_as_email = isset( $_POST['sendAsEmail'] ) ? ( 'true' === $_POST['sendAsEmail'] ) : false;
165
166
		/**
167
		 * Filters the array of exporter callbacks.
168
		 *
169
		 * @since 1.6.26
170
		 *
171
		 * @param array $args {
172
		 *     An array of callable exporters of personal data. Default empty array.
173
		 *
174
		 *     @type array {
175
		 *         Array of personal data exporters.
176
		 *
177
		 *         @type string $callback               Callable exporter function that accepts an
178
		 *                                              email address and a page and returns an array
179
		 *                                              of name => value pairs of personal data.
180
		 *         @type string $exporter_friendly_name Translated user facing friendly name for the
181
		 *                                              exporter.
182
		 *     }
183
		 * }
184
		 */
185
		$exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() );
186
187
		if ( ! is_array( $exporters ) ) {
188
			return false;
189
		}
190
191
		// Do we have any registered exporters?
192
		if ( 0 < count( $exporters ) ) {
193
			if ( $exporter_index < 1 ) {
194
				return false;
195
			}
196
197
			if ( $exporter_index > count( $exporters ) ) {
198
				return false;
199
			}
200
201
			if ( $page < 1 ) {
202
				return false;
203
			}
204
205
			$exporter_keys = array_keys( $exporters );
206
			$exporter_key  = $exporter_keys[ $exporter_index - 1 ];
207
			$exporter      = $exporters[ $exporter_key ];
208
			
209
			if ( ! is_array( $exporter ) || empty( $exporter_key ) ) {
210
				return false;
211
			}
212
			if ( ! array_key_exists( 'exporter_friendly_name', $exporter ) ) {
213
				return false;
214
			}
215
			if ( ! array_key_exists( 'callback', $exporter ) ) {
216
				return false;
217
			}
218
		}
219
220
		/**
221
		 * Filters a page of personal data exporter.
222
		 *
223
		 * @since 1.6.26
224
		 *
225
		 * @param array  $exporter_key    The key (slug) of the exporter that provided this data.
226
		 * @param array  $exporter        The personal data for the given exporter.
227
		 * @param int    $exporter_index  The index of the exporter that provided this data.
228
		 * @param string $email_address   The email address associated with this personal data.
229
		 * @param int    $page            The page for this response.
230
		 * @param int    $request_id      The privacy request post ID associated with this request.
231
		 * @param bool   $send_as_email   Whether the final results of the export should be emailed to the user.
232
		 */
233
		$exporter_key = apply_filters( 'geodir_privacy_personal_data_exporter', $exporter_key, $exporter, $exporter_index, $email_address, $page, $request_id, $send_as_email );
0 ignored issues
show
Bug introduced by
The variable $exporter_key does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $exporter does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
234
235
		return $exporter_key;
236
	}
237
238
	public static function exporter_post_type() {
239
		$exporter_key = self::personal_data_exporter_key();
240
241
		if ( empty( $exporter_key ) ) {
242
			return false;
243
		}
244
245
		if ( strpos( $exporter_key, 'geodirectory-post-' ) !== 0 ) {
246
			return false;
247
		}
248
249
		$post_type = str_replace( 'geodirectory-post-', '', $exporter_key );
250
251
		if ( $post_type != '' && in_array( $post_type, geodir_get_posttypes() ) ) {
252
			return $post_type;
253
		}
254
255
		return false;
256
	}
257
258
	public static function allow_export_post_type_data( $post_type ) {
259
		$allow = true;
260
261
		return apply_filters( 'geodir_privacy_allow_export_post_type_data', $allow, $post_type );
262
	}
263
264
	public static function allow_export_reviews_data() {
265
		$allow = true;
266
267
		return apply_filters( 'geodir_privacy_allow_export_reviews_data', $allow );
268
	}
269
270
	public static function allow_erase_reviews_data() {
271
		$allow = true;
272
273
		return apply_filters( 'geodir_privacy_allow_erase_reviews_data', $allow );
274
	}
275
276
	public static function allow_export_favorites_data() {
277
		$allow = true;
278
279
		return apply_filters( 'geodir_privacy_allow_export_favorites_data', $allow );
280
	}
281
282
	public static function allow_erase_favorites_data() {
283
		$allow = true;
284
285
		return apply_filters( 'geodir_privacy_allow_erase_favorites_data', $allow );
286
	}
287
288
	public static function favorites_by_user( $email_address, $page ) {
0 ignored issues
show
Unused Code introduced by
The parameter $page is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
289
		if ( empty( $email_address ) ) {
290
			return array();
291
		}
292
293
		$user = get_user_by( 'email', $email_address );
294
		if ( empty( $user ) ) {
295
			return array();
296
		}
297
298
		$favourites = geodir_get_user_favourites( $user->ID );
299
300
		return ( ! empty( $favourites ) && is_array( $favourites ) ? $favourites : array() );
301
	}
302
}
303
304
new GeoDir_Privacy();
305