Completed
Branch EDTR/master (2c3e96)
by
unknown
19:06 queued 09:20
created

EEH_Sideloader::isDownloadError()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 4
nop 1
dl 0
loc 25
rs 9.2088
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * EEH_Sideloader
5
 *
6
 * This is a helper utility class that provides "sideloading" functionality.
7
 * Sideloading simply refers to retrieving files hosted elsewhere
8
 * (usually github) that are downloaded into EE.
9
 *
10
 * @package     Event Espresso
11
 * @subpackage  /helpers/EEH_Sideloader.helper.php
12
 * @author      Darren Ethier
13
 */
14
class EEH_Sideloader extends EEH_Base
15
{
16
17
    /**
18
     * @since   4.1.0
19
     * @var     string
20
     */
21
    private $_upload_to;
22
23
    /**
24
     * @since   4.10.5.p
25
     * @var     string
26
     */
27
    private $_download_from;
28
29
    /**
30
     * @since   4.1.0
31
     * @var     string
32
     */
33
    private $_permissions;
34
35
    /**
36
     * @since   4.1.0
37
     * @var     string
38
     */
39
    private $_new_file_name;
40
41
42
    /**
43
     * constructor allows the user to set the properties on the sideloader on construct.  However, there are also
44
     * setters for doing so.
45
     *
46
     * @param array $init array fo initializing the sideloader if keys match the properties.
47
     * @since 4.1.0
48
     */
49
    public function __construct($init = [])
50
    {
51
        $this->_init($init);
52
    }
53
54
55
    /**
56
     * sets the properties for class either to defaults or using incoming initialization array
57
     *
58
     * @param array $init array on init (keys match properties others ignored)
59
     * @return void
60
     * @since 4.1.0
61
     */
62
    private function _init($init)
63
    {
64
        $defaults = [
65
            '_upload_to'     => $this->_get_wp_uploads_dir(),
66
            '_download_from' => '',
67
            '_permissions'   => 0644,
68
            '_new_file_name' => 'EE_Sideloader_' . uniqid() . '.default',
69
        ];
70
71
        $props = array_merge($defaults, $init);
72
73
        foreach ($props as $property => $val) {
74
            $setter = 'set' . $property;
75 View Code Duplication
            if (method_exists($this, $setter)) {
76
                $this->$setter($val);
77
            } else {
78
                // No setter found.
79
                EE_Error::add_error(
80
                    sprintf(
81
                        esc_html__(
82
                            'EEH_Sideloader::%1$s not found. There is no setter for the %2$s property.',
83
                            'event_espresso'
84
                        ),
85
                        $setter,
86
                        $property
87
                    ),
88
                    __FILE__,
89
                    __FUNCTION__,
90
                    __LINE__
91
                );
92
            }
93
        }
94
95
        // make sure we include the required wp file for needed functions
96
        require_once(ABSPATH . 'wp-admin/includes/file.php');
97
    }
98
99
100
    // utilities
101
102
103
    /**
104
     * @return string
105
     * @since 4.1.0
106
     */
107
    private function _get_wp_uploads_dir()
108
    {
109
        $uploads = wp_upload_dir();
110
        return $uploads['basedir'];
111
    }
112
113
    // setters
114
115
116
    /**
117
     * sets the _upload_to property to the directory to upload to.
118
     *
119
     * @param $upload_to_folder
120
     * @return void
121
     * @since 4.1.0
122
     */
123
    public function set_upload_to($upload_to_folder)
124
    {
125
        $this->_upload_to = $upload_to_folder;
126
    }
127
128
129
    /**
130
     * sets the _download_from property to the location we should download the file from.
131
     *
132
     * @param string $download_from The full path to the file we should sideload.
133
     * @return void
134
     * @since 4.10.5.p
135
     */
136
    public function set_download_from($download_from)
137
    {
138
        $this->_download_from = $download_from;
139
    }
140
141
142
    /**
143
     * sets the _permissions property used on the sideloaded file.
144
     *
145
     * @param int $permissions
146
     * @return void
147
     * @since 4.1.0
148
     */
149
    public function set_permissions($permissions)
150
    {
151
        $this->_permissions = $permissions;
152
    }
153
154
155
    /**
156
     * sets the _new_file_name property used on the sideloaded file.
157
     *
158
     * @param string $new_file_name
159
     * @return void
160
     * @since 4.1.0
161
     */
162
    public function set_new_file_name($new_file_name)
163
    {
164
        $this->_new_file_name = $new_file_name;
165
    }
166
167
    // getters
168
169
170
    /**
171
     * @return string
172
     * @since 4.1.0
173
     */
174
    public function get_upload_to()
175
    {
176
        return $this->_upload_to;
177
    }
178
179
180
    /**
181
     * @return string
182
     * @since 4.10.5.p
183
     */
184
    public function get_download_from()
185
    {
186
        return $this->_download_from;
187
    }
188
189
190
    /**
191
     * @return int
192
     * @since 4.1.0
193
     */
194
    public function get_permissions()
195
    {
196
        return $this->_permissions;
197
    }
198
199
200
    /**
201
     * @return string
202
     * @since 4.1.0
203
     */
204
    public function get_new_file_name()
205
    {
206
        return $this->_new_file_name;
207
    }
208
209
210
    // upload methods
211
212
213
    /**
214
     * Downloads the file using the WordPress HTTP API.
215
     *
216
     * @return bool
217
     * @since 4.1.0
218
     */
219
    public function sideload()
220
    {
221
        try {
222
            // setup temp dir
223
            $temp_file = wp_tempnam($this->_download_from);
224
225
            if (! $temp_file) {
226
                throw new RuntimeException(
227
                    esc_html__(
228
                        'Something went wrong with the upload.  Unable to create a tmp file for the uploaded file on the server',
229
                        'event_espresso'
230
                    )
231
                );
232
            }
233
234
            do_action('AHEE__EEH_Sideloader__sideload__before', $this, $temp_file);
235
236
            $wp_remote_args = apply_filters(
237
                'FHEE__EEH_Sideloader__sideload__wp_remote_args',
238
                ['timeout' => 500, 'stream' => true, 'filename' => $temp_file],
239
                $this,
240
                $temp_file
241
            );
242
243
            $response = wp_safe_remote_get($this->_download_from, $wp_remote_args);
244
245
            if ($this->isResponseError($response) || $this->isDownloadError($response)) {
246
                EEH_File::delete($temp_file);
247
                return false;
248
            }
249
250
            // possible md5 check
251
            $content_md5 = wp_remote_retrieve_header($response, 'content-md5');
252
            if ($content_md5) {
253
                $md5_check = verify_file_md5($temp_file, $content_md5);
254
                if ($this->isResponseError($md5_check)) {
255
                    EEH_File::delete($temp_file);
256
                    return false;
257
                }
258
            }
259
260
            // now we have the file, let's get it in the right directory with the right name.
261
            $path  = apply_filters(
262
                'FHEE__EEH_Sideloader__sideload__new_path',
263
                $this->_upload_to . $this->_new_file_name,
264
                $this
265
            );
266
            if (! EEH_File::move($temp_file, $path, true)) {
267
                return false;
268
            }
269
270
            // set permissions
271
            $permissions = apply_filters(
272
                'FHEE__EEH_Sideloader__sideload__permissions_applied',
273
                $this->_permissions,
274
                $this
275
            );
276
            // verify permissions are an integer but don't actually modify the value
277
            $perms = absint($permissions);
278
            if (! $perms) {
279
                EE_Error::add_error(
280
                    esc_html__('Supplied permissions are invalid', 'event_espresso'),
281
                    __FILE__,
282
                    __FUNCTION__,
283
                    __LINE__
284
                );
285
                return false;
286
            }
287
            EEH_File::chmod($path, $permissions);
288
289
            // that's it.  let's allow for actions after file uploaded.
290
            do_action('AHEE__EE_Sideloader__sideload_after', $this, $path);
291
            return true;
292
        } catch (Exception $exception) {
293
            EE_Error::add_error($exception->getMessage(), __FILE__, __FUNCTION__, __LINE__);
294
            return false;
295
        }
296
    }
297
298
299
    /**
300
     * returns TRUE if there IS an error, FALSE if there is NO ERROR
301
     *
302
     * @param array|WP_Error $response
303
     * @return bool
304
     * @throws RuntimeException
305
     */
306
    private function isResponseError($response)
307
    {
308
        if (! is_wp_error($response)) {
309
            return false;
310
        }
311
        if (defined('WP_DEBUG') && WP_DEBUG) {
312
            EE_Error::add_error(
313
                sprintf(
314
                    esc_html__(
315
                        'The following error occurred while attempting to download the file from "%1$s":',
316
                        'event_espresso'
317
                    ),
318
                    $this->_download_from,
319
                    $response->get_error_message()
320
                ),
321
                __FILE__,
322
                __FUNCTION__,
323
                __LINE__
324
            );
325
        }
326
        return true;
327
    }
328
329
330
    /**
331
     * returns TRUE if there IS an error, FALSE if there is NO ERROR
332
     *
333
     * @param array  $response
334
     * @return bool
335
     * @throws RuntimeException
336
     */
337
    private function isDownloadError(array $response)
338
    {
339
        $response_code = wp_remote_retrieve_response_code($response);
340
        if ($response_code === 200) {
341
            return false;
342
        }
343
        if (defined('WP_DEBUG') && WP_DEBUG) {
344
            $msg = $response_code === 404
345
                ? esc_html__(
346
                    'Attempted to download a file from "%1$s" but encountered a "404 File Not Found" error.',
347
                    'event_espresso'
348
                )
349
                : esc_html__(
350
                    'Unable to download the file. Either the path given is incorrect, or something else happened. Here is the path given: %s',
351
                    'event_espresso'
352
                );
353
            EE_Error::add_error(
354
                sprintf($msg, $this->_download_from),
355
                __FILE__,
356
                __FUNCTION__,
357
                __LINE__
358
            );
359
        }
360
        return true;
361
    }
362
363
    // deprecated
364
365
    /**
366
     * sets the _upload_from property to the location we should download the file from.
367
     *
368
     * @param string $upload_from The full path to the file we should sideload.
369
     * @return void
370
     * @deprecated since version 4.10.5.p
371
     */
372
    public function set_upload_from($upload_from)
373
    {
374
        EE_Error::doing_it_wrong(
375
            __CLASS__ . '::' . __FUNCTION__,
376
            __(
377
                'EEH_Sideloader::set_upload_from was renamed to EEH_Sideloader::set_download_from',
378
                'event_espresso'
379
            ),
380
            '4.10.5.p'
381
        );
382
        $this->set_download_from($upload_from);
383
    }
384
385
386
    /**
387
     * @return string
388
     * @since      4.1.0
389
     * @deprecated since version 4.10.5.p
390
     */
391
    public function get_upload_from()
392
    {
393
        EE_Error::doing_it_wrong(
394
            __CLASS__ . '::' . __FUNCTION__,
395
            __(
396
                'EEH_Sideloader::get_upload_from was renamed to EEH_Sideloader::get_download_from',
397
                'event_espresso'
398
            ),
399
            '4.10.5.p'
400
        );
401
        return $this->_download_from;
402
    }
403
} //end EEH_Sideloader class
404