ExternalURLCheck::getCurlOpts()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\EnvironmentCheck\Checks;
4
5
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
6
7
/**
8
 * Checks that one or more URLs are reachable via HTTP.
9
 * Note that the HTTP connectivity can just be verified from the server to the remote URL,
10
 * it can still fail if the URL in question is requested by the client, e.g. through an iframe.
11
 *
12
 * Requires curl to present, so ensure to check it before with the following:
13
 * <code>
14
 * EnvironmentCheckSuite::register(
15
 *     'check',
16
 *     'HasFunctionCheck("curl_init")',
17
 *     "Does PHP have CURL support?"
18
 * );
19
 * </code>
20
 */
21
class ExternalURLCheck implements EnvironmentCheck
22
{
23
    /**
24
     * @var array
25
     */
26
    protected $urls = [];
27
28
    /**
29
     * @var Int Timeout in seconds.
30
     */
31
    protected $timeout;
32
33
    /**
34
     * @param string $urls Space-separated list of absolute URLs.
35
     * @param int $timeout
36
     */
37
    public function __construct($urls, $timeout = 15)
38
    {
39
        if ($urls) {
40
            $this->urls = explode(' ', $urls);
41
        }
42
        $this->timeout = $timeout;
43
    }
44
45
    /**
46
     * {@inheritDoc}
47
     *
48
     * @return array
49
     */
50
    public function check()
51
    {
52
        $urls = $this->getURLs();
53
54
        $chs = [];
55
        foreach ($urls as $url) {
56
            $ch = curl_init();
57
            $chs[] = $ch;
58
            curl_setopt_array($ch, $this->getCurlOpts($url));
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt_array() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

58
            curl_setopt_array(/** @scrutinizer ignore-type */ $ch, $this->getCurlOpts($url));
Loading history...
59
        }
60
        // Parallel execution for faster performance
61
        $mh = curl_multi_init();
62
        foreach ($chs as $ch) {
63
            curl_multi_add_handle($mh, $ch);
64
        }
65
66
        $active = null;
67
        // Execute the handles
68
        do {
69
            $mrc = curl_multi_exec($mh, $active);
70
            curl_multi_select($mh);
71
        } while ($active > 0);
72
73
        while ($active && $mrc == CURLM_OK) {
74
            if (curl_multi_select($mh) != -1) {
75
                do {
76
                    $mrc = curl_multi_exec($mh, $active);
77
                } while ($mrc == CURLM_CALL_MULTI_PERFORM);
78
            }
79
        }
80
81
        $hasError = false;
82
        $msgs = [];
83
        foreach ($chs as $ch) {
84
            $url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
85
            $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
86
            if (curl_errno($ch) || $code >= 400) {
87
                $hasError = true;
88
                $msgs[] = sprintf(
89
                    'Error retrieving "%s": %s (Code: %s)',
90
                    $url,
91
                    curl_error($ch),
92
                    $code
93
                );
94
            } else {
95
                $msgs[] = sprintf(
96
                    'Success retrieving "%s" (Code: %s)',
97
                    $url,
98
                    $code
99
                );
100
            }
101
        }
102
103
        // Close the handles
104
        foreach ($chs as $ch) {
105
            curl_multi_remove_handle($mh, $ch);
106
        }
107
        curl_multi_close($mh);
108
109
        if ($hasError) {
110
            return [EnvironmentCheck::ERROR, implode(', ', $msgs)];
111
        }
112
113
        return [EnvironmentCheck::OK, implode(', ', $msgs)];
114
    }
115
116
    /**
117
     * @return array
118
     */
119
    protected function getCurlOpts($url)
120
    {
121
        return [
122
            CURLOPT_URL => $url,
123
            CURLOPT_HEADER => 0,
124
            CURLOPT_RETURNTRANSFER => 1,
125
            CURLOPT_FAILONERROR => 1,
126
            CURLOPT_TIMEOUT => $this->timeout,
127
        ];
128
    }
129
130
    /**
131
     * @return array
132
     */
133
    protected function getURLs()
134
    {
135
        return $this->urls;
136
    }
137
}
138