Passed
Push — master ( f3c4c9...486eac )
by Paul
16:32 queued 07:47
created

Updater::getTransientName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 1 Features 1
Metric Value
eloc 1
c 1
b 1
f 1
dl 0
loc 3
ccs 0
cts 3
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Addons;
4
5
use GeminiLabs\SiteReviews\Helper;
6
use GeminiLabs\SiteReviews\Helpers\Arr;
7
use GeminiLabs\SiteReviews\Helpers\Url;
8
9
class Updater
10
{
11
    /**
12
     * @var string
13
     */
14
    protected $apiUrl;
15
    /**
16
     * @var array
17
     */
18
    protected $data;
19
    /**
20
     * @var string
21
     */
22
    protected $plugin;
23
24
    /**
25
     * @param string $apiUrl
26
     * @param string $file
27
     */
28
    public function __construct($apiUrl, $file, array $data = [])
29
    {
30
        if (!function_exists('get_plugin_data')) {
31
            require_once ABSPATH.WPINC.'/plugin.php';
32
        }
33
        $this->apiUrl = trailingslashit(glsr()->filterString('addon/api-url', $apiUrl));
34
        $this->data = wp_parse_args($data, get_plugin_data($file));
35
        $this->plugin = plugin_basename($file);
36
    }
37
38
    /**
39
     * @return object
40
     */
41
    public function activateLicense(array $data = [])
42
    {
43
        return $this->request('activate_license', $data);
44
    }
45
46
    /**
47
     * @return object
48
     */
49
    public function checkLicense(array $data = [])
50
    {
51
        $response = $this->request('check_license', $data);
52
        if ('valid' === Arr::get($response, 'license')) {
53
            $this->getPluginUpdate(true);
54
        }
55
        return $response;
56
    }
57
58
    /**
59
     * @return object
60
     */
61
    public function deactivateLicense(array $data = [])
62
    {
63
        return $this->request('deactivate_license', $data);
64
    }
65
66
    /**
67
     * @param false|object|array $result
68
     * @param string $action
69
     * @param object $args
70
     * @return mixed
71
     */
72
    public function filterPluginUpdateDetails($result, $action, $args)
73
    {
74
        if ('plugin_information' != $action
75
            || Arr::get($this->data, 'TextDomain') != Arr::get($args, 'slug')) {
76
            return $result;
77
        }
78
        if ($updateInfo = $this->getPluginUpdate()) {
79
            return $this->modifyUpdateDetails($updateInfo);
80
        }
81
        return $result;
82
    }
83
84
    /**
85
     * @param object $transient
86
     * @return object
87
     */
88
    public function filterPluginUpdates($transient)
89
    {
90
        if ($updateInfo = $this->getPluginUpdate()) {
91
            return $this->modifyPluginUpdates($transient, $updateInfo);
92
        }
93
        return $transient;
94
    }
95
96
    /**
97
     * @return object
98
     */
99
    public function getVersion(array $data = [])
100
    {
101
        return $this->request('get_version', $data);
102
    }
103
104
    /**
105
     * @return void
106
     */
107
    public function init()
108
    {
109
        if ($this->apiUrl === Url::home()) {
110
            return;
111
        }
112
        add_filter('plugins_api', [$this, 'filterPluginUpdateDetails'], 10, 3);
113
        add_filter('pre_set_site_transient_update_plugins', [$this, 'filterPluginUpdates'], 999);
114
        add_action('load-update-core.php', [$this, 'onForceUpdateCheck'], 9);
115
        add_action('in_plugin_update_message-'.$this->plugin, [$this, 'renderLicenseMissingLink']);
116
    }
117
118
    /**
119
     * @return bool
120
     */
121
    public function isLicenseValid()
122
    {
123
        $result = $this->checkLicense();
124
        return 'valid' === Arr::get($result, 'license');
125
    }
126
127
    /**
128
     * @return void
129
     */
130
    public function onForceUpdateCheck()
131
    {
132
        if (!filter_input(INPUT_GET, 'force-check')) {
133
            return;
134
        }
135
        try {
136
            $this->getPluginUpdate(true);
137
        } catch (\Exception $e) {
138
            glsr_log()->error($e->getMessage());
139
        }
140
    }
141
142
    /**
143
     * @return void
144
     */
145
    public function renderLicenseMissingLink()
146
    {
147
        if (!$this->isLicenseValid()) {
148
            glsr()->render('partials/addons/license-missing');
149
        }
150
    }
151
152
    /**
153
     * @return false|object
154
     */
155
    protected function getCachedVersion()
156
    {
157
        return get_transient($this->getTransientName());
158
    }
159
160
    /**
161
     * @param bool $force
162
     * @return false|object
163
     */
164
    protected function getPluginUpdate($force = false)
165
    {
166
        $version = $this->getCachedVersion();
167
        if (false === $version || false !== $force) {
168
            $version = $this->getVersion();
169
            $this->setCachedVersion($version);
170
        }
171
        if (isset($version->error)) {
172
            glsr_log()->error($version->error);
173
            return false;
174
        }
175
        return $version;
176
    }
177
178
    /**
179
     * @return string
180
     */
181
    protected function getTransientName()
182
    {
183
        return glsr()->prefix.md5(Arr::get($this->data, 'TextDomain'));
184
    }
185
186
    /**
187
     * @param object $transient
188
     * @param object $updateInfo
189
     * @return object
190
     */
191
    protected function modifyPluginUpdates($transient, $updateInfo)
192
    {
193
        $updateInfo->id = glsr()->id.'/'.Arr::get($this->data, 'TextDomain');
194
        $updateInfo->plugin = $this->plugin;
195
        // $updateInfo->requires_php = Arr::get($this->data, 'RequiresPHP');
196
        // $updateInfo->tested = Arr::get($this->data, 'testedTo');
197
        unset($updateInfo->upgrade_notice); // @todo for some reason, this is returned as an array
198
        $transient->checked[$this->plugin] = Arr::get($this->data, 'Version');
199
        $transient->last_checked = time();
200
        if (Helper::isGreaterThan($updateInfo->new_version, Arr::get($this->data, 'Version'))) {
201
            unset($transient->no_update[$this->plugin]);
202
            $updateInfo->update = true;
203
            $transient->response[$this->plugin] = $updateInfo;
204
        } else {
205
            unset($transient->response[$this->plugin]);
206
            $transient->no_update[$this->plugin] = $updateInfo;
207
        }
208
        return $transient;
209
    }
210
211
    /**
212
     * @param object $updateInfo
213
     * @return object
214
     */
215
    protected function modifyUpdateDetails($updateInfo)
216
    {
217
        $updateInfo->author = Arr::get($this->data, 'Author');
218
        $updateInfo->author_profile = Arr::get($this->data, 'AuthorURI');
219
        // $updateInfo->requires = Arr::get($this->data, 'RequiresWP');
220
        // $updateInfo->requires_php = Arr::get($this->data, 'RequiresPHP');
221
        // $updateInfo->tested = Arr::get($this->data, 'testedTo');
222
        $updateInfo->version = $updateInfo->new_version;
223
        unset($updateInfo->contributors); // @todo for some reason, this is not being parsed as an array
224
        return $updateInfo;
225
    }
226
227
    /**
228
     * @param \WP_Error|array $response
229
     * @return object
230
     */
231
    protected function normalizeResponse($response)
232
    {
233
        $body = wp_remote_retrieve_body($response);
234
        if ($data = json_decode($body)) {
235
            $data = array_map('maybe_unserialize', (array) $data);
236
            return (object) $data;
237
        }
238
        $error = is_wp_error($response)
239
            ? $response->get_error_message()
240
            : 'Update server not responding ('.Arr::get($this->data, 'TextDomain').')';
241
        return (object) ['error' => $error];
242
    }
243
244
    /**
245
     * @param string $action activate_license|check_license|deactivate_license|get_version
246
     * @return object
247
     */
248
    protected function request($action, array $data = [])
249
    {
250
        $data = wp_parse_args($data, $this->data);
251
        $response = wp_remote_post($this->apiUrl, [
252
            'body' => [
253
                'edd_action' => $action,
254
                'item_id' => '', // we don't have access to the download ID which is why this is empty
255
                'item_name' => Arr::get($data, 'TextDomain'), // we are using the slug for the name
256
                'license' => Arr::get($data, 'license'),
257
                'slug' => Arr::get($data, 'TextDomain'),
258
                'url' => Url::home(),
259
            ],
260
            'sslverify' => glsr()->filterBool('sslverify/post', false),
261
            'timeout' => 15,
262
        ]);
263
        return $this->normalizeResponse($response);
264
    }
265
266
    /**
267
     * @param object $version
268
     * @return void
269
     */
270
    protected function setCachedVersion($version)
271
    {
272
        if (!isset($version->error)) {
273
            set_transient($this->getTransientName(), $version, 3 * HOUR_IN_SECONDS);
274
        }
275
    }
276
}
277