Completed
Push — master ( ffda11...ab397f )
by Stephanie
06:42
created

FrmEDD_SL_Plugin_Updater::api_request()   C

Complexity

Conditions 10
Paths 42

Size

Total Lines 47
Code Lines 29

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 47
rs 5.1579
cc 10
eloc 29
nc 42
nop 2

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
// uncomment this line for testing
4
//set_site_transient( 'update_plugins', null );
5
6
// Exit if accessed directly
7
if ( ! defined( 'ABSPATH' ) ) {
8
	exit;
9
}
10
11
/**
12
 * Allows plugins to use their own update API.
13
 *
14
 * @author Pippin Williamson
15
 * @version 1.6
16
 */
17
class FrmEDD_SL_Plugin_Updater {
18
    private $api_url   = '';
19
    private $api_data  = array();
20
    private $name      = '';
21
    private $slug      = '';
22
    private $version   = '';
23
24
    /**
25
     * Class constructor.
26
     *
27
     * @uses plugin_basename()
28
     * @uses hook()
29
     *
30
     * @param string  $_api_url     The URL pointing to the custom API endpoint.
31
     * @param string  $_plugin_file Path to the plugin file.
32
     * @param array   $_api_data    Optional data to send with API calls.
33
     */
34
    public function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
35
        $this->api_url  = trailingslashit( $_api_url );
36
        $this->api_data = $_api_data;
0 ignored issues
show
Documentation Bug introduced by
It seems like $_api_data can be null. However, the property $api_data is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
37
        $this->name     = plugin_basename( $_plugin_file );
38
        $this->slug     = basename( $_plugin_file, '.php' );
39
        $this->version  = $_api_data['version'];
40
41
        // Set up hooks.
42
        $this->init();
43
        add_action( 'admin_init', array( $this, 'show_changelog' ) );
44
    }
45
46
    /**
47
     * Set up WordPress filters to hook into WP's update process.
48
     *
49
     * @uses add_filter()
50
     *
51
     * @return void
52
     */
53
    public function init() {
54
        add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
55
        add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
56
    }
57
58
    /**
59
     * Check for Updates at the defined API endpoint and modify the update array.
60
     *
61
     * This function dives into the update API just when WordPress creates its update array,
62
     * then adds a custom API call and injects the custom plugin data retrieved from the API.
63
     * It is reassembled from parts of the native WordPress plugin update code.
64
     * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
65
     *
66
     * @uses api_request()
67
     *
68
     * @param array   $_transient_data Update array build by WordPress.
69
     * @return array Modified update array with custom plugin data.
70
     */
71
    public function check_update( $_transient_data ) {
72
73
        global $pagenow;
74
75
        if ( ! is_object( $_transient_data ) ) {
76
            $_transient_data = new stdClass;
77
        }
78
79
        if ( empty( $_transient_data->response ) || empty( $_transient_data->response[ $this->name ] ) ) {
80
81
            $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug ) );
82
83
            if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
84
85
                if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
86
87
					if ( empty( $version_info->plugin ) ) {
88
						$version_info->plugin = $this->name;
89
					}
90
91
                    $_transient_data->response[ $this->name ] = $version_info;
92
93
                }
94
95
                $_transient_data->last_checked = time();
96
                $_transient_data->checked[ $this->name ] = $this->version;
97
98
            }
99
        }
100
101
        return $_transient_data;
102
    }
103
104
    /**
105
     * Updates information on the "View version x.x details" page with custom data.
106
     *
107
     * @uses api_request()
108
     *
109
     * @param mixed   $_data
110
     * @param string  $_action
111
     * @param object  $_args
112
     * @return object $_data
113
     */
114
    public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
115
116
        if ( $_action != 'plugin_information' ) {
117
118
            return $_data;
119
120
        }
121
122
        if ( ! isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) {
123
124
            return $_data;
125
126
        }
127
128
        $to_send = array(
129
            'slug'   => $this->slug,
130
            'is_ssl' => is_ssl(),
131
            'fields' => array(
132
                'banners' => false, // These will be supported soon hopefully
133
                'reviews' => false,
134
            ),
135
        );
136
137
        $api_response = $this->api_request( 'plugin_information', $to_send );
138
139
        if ( false !== $api_response ) {
140
            $_data = $api_response;
141
        }
142
143
        return $_data;
144
    }
145
146
147
    /**
148
     * Disable SSL verification in order to prevent download update failures
149
     *
150
     * @param array   $args
151
     * @param string  $url
152
     * @return object $array
153
     */
154
    public function http_request_args( $args, $url ) {
155
        // If it is an https request and we are performing a package download, disable ssl verification
156
        if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
157
            $args['sslverify'] = false;
158
        }
159
        return $args;
160
    }
161
162
    /**
163
     * Calls the API and, if successfull, returns the object delivered by the API.
164
     *
165
     * @uses get_bloginfo()
166
     * @uses wp_remote_post()
167
     * @uses is_wp_error()
168
     *
169
     * @param string  $_action The requested action.
170
     * @param array   $_data   Parameters for the API action.
171
     * @return false|object
172
     */
173
    private function api_request( $_action, $_data ) {
0 ignored issues
show
Unused Code introduced by
The parameter $_action 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...
174
175
        global $wp_version;
176
177
        $data = array_merge( $this->api_data, $_data );
178
179
        if ( $data['slug'] != $this->slug ) {
180
            return;
181
		}
182
183
        if ( $this->api_url == home_url() ) {
184
            return false; // Don't allow a plugin to ping itself
185
        }
186
187
        $api_params = array(
188
            'edd_action' => 'get_version',
189
            'license'    => ! empty( $data['license'] ) ? $data['license'] : '',
190
            'item_name'  => isset( $data['item_name'] ) ? $data['item_name'] : false,
191
            'item_id'    => isset( $data['item_id'] ) ? $data['item_id'] : false,
192
            'slug'       => $data['slug'],
193
            'author'     => $data['author'],
194
            'url'        => home_url(),
195
        );
196
197
		$cache_key = 'edd_plugin_' . md5( sanitize_key( $api_params['license'] . $this->version ) . '_' . $api_params['edd_action'] );
198
		$cached_response = get_transient( $cache_key );
199
		if ( $cached_response !== false ) {
200
			// if this has been checked within 24 hours, don't check again
201
			return $cached_response;
202
		}
203
204
        $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => false, 'body' => $api_params ) );
205
206
        if ( ! is_wp_error( $request ) ) {
207
            $request = json_decode( wp_remote_retrieve_body( $request ) );
208
        }
209
210
        if ( $request && isset( $request->sections ) ) {
211
            $request->sections = maybe_unserialize( $request->sections );
212
			set_transient( $cache_key, $request, DAY_IN_SECONDS );
213
        } else {
214
            $request = false;
215
			set_transient( $cache_key, 0, DAY_IN_SECONDS );
216
        }
217
218
        return $request;
219
    }
220
221
    public function show_changelog() {
222
223
        if ( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' != $_REQUEST['edd_sl_action'] ) {
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
224
            return;
225
        }
226
227
        if ( empty( $_REQUEST['plugin'] ) ) {
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
228
            return;
229
        }
230
231
        if ( empty( $_REQUEST['slug'] ) ) {
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
232
            return;
233
        }
234
235
        if ( ! current_user_can( 'update_plugins' ) ) {
236
            wp_die( __( 'You do not have permission to install plugin updates', 'edd' ), __( 'Error', 'edd' ), array( 'response' => 403 ) );
237
        }
238
239
        $response = $this->api_request( 'plugin_latest_version', array( 'slug' => $_REQUEST['slug'] ) );
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
240
241
        if ( $response && isset( $response->sections['changelog'] ) ) {
242
            echo '<div style="background:#fff;padding:10px;">' . $response->sections['changelog'] . '</div>';
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$response'
Loading history...
243
        }
244
245
        exit;
246
    }
247
}
248