Completed
Push — master ( e090e4...18d79e )
by Damian
02:26
created

code/checks/ExternalURLCheck.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Checks that one or more URLs are reachable via HTTP.
5
 * Note that the HTTP connectivity can just be verified from the server to the remote URL,
6
 * it can still fail if the URL in question is requested by the client, e.g. through an iframe.
7
 * 
8
 * Requires curl to present, so ensure to check it before with the following:
9
 * <code>EnvironmentCheckSuite::register('check', 'HasFunctionCheck("curl_init")', "Does PHP have CURL support?");</code>
10
 */
11
class ExternalURLCheck implements EnvironmentCheck {
0 ignored issues
show
As per PSR2, the opening brace for this class should be on a new line.
Loading history...
12
	/**
13
	 * @var array
14
	 */
15
	protected $urls = array();
16
17
	/**
18
	 * @var Int Timeout in seconds.
19
	 */
20
	protected $timeout;
21
22
	/**
23
	 * @param string $urls Space-separated list of absolute URLs.
24
	 * @param int $timeout
25
	 */
26
	function __construct($urls, $timeout = 15) {
0 ignored issues
show
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
27
		if($urls) $this->urls = explode(' ', $urls);
28
		$this->timeout = $timeout;
29
	}
30
31
	/**
32
	 * @inheritdoc
33
	 *
34
	 * @return array
35
	 */
36
	function check() {
0 ignored issues
show
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
37
		$urls = $this->getURLs();
38
39
		$chs = array();
40
		foreach($urls as $url)	{
41
			$ch = curl_init();
42
			$chs[] = $ch;
43
			curl_setopt_array($ch, $this->getCurlOpts($url));
44
		}	
45
		// Parallel execution for faster performance
46
		$mh = curl_multi_init();
47
		foreach($chs as $ch) curl_multi_add_handle($mh,$ch);
48
		
49
		$active = null;
50
		// Execute the handles
51
		do {
52
			$mrc = curl_multi_exec($mh, $active);
53
			curl_multi_select($mh);
54
		} while ($active > 0);
55
56
		while ($active && $mrc == CURLM_OK) {
57
			if (curl_multi_select($mh) != -1) {
58
				do {
59
						$mrc = curl_multi_exec($mh, $active);
60
				} while ($mrc == CURLM_CALL_MULTI_PERFORM);
61
			}
62
		}
63
64
		$hasError = false;
65
		$msgs = array();
66
		foreach($chs as $ch) {
67
			$url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
68
			$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
69
			if(curl_errno($ch) || $code >= 400) {
70
				$hasError = true;
71
				$msgs[] = sprintf(
72
					'Error retrieving "%s": %s (Code: %s)',
73
					$url,
74
					curl_error($ch),
75
					$code
76
				);
77
			} else {
78
				$msgs[] = sprintf(
79
					'Success retrieving "%s" (Code: %s)',
80
					$url,
81
					$code
82
				);
83
			}
84
		}
85
86
		// Close the handles
87
		foreach($chs as $ch) curl_multi_remove_handle($mh, $ch);
88
		curl_multi_close($mh);
89
		
90
		if($hasError) {
91
			return array(EnvironmentCheck::ERROR, implode(', ', $msgs));
92
		} else {
93
			return array(EnvironmentCheck::OK, implode(', ', $msgs));
94
		}
95
	}
96
97
	/**
98
	 * @return array
99
	 */
100
	protected function getCurlOpts($url) {
101
		return array(
102
			CURLOPT_URL => $url,
103
			CURLOPT_HEADER => 0,
104
			CURLOPT_RETURNTRANSFER => 1,
105
			CURLOPT_FAILONERROR => 1,
106
			CURLOPT_TIMEOUT => $this->timeout,
107
		);
108
	}
109
110
	/**
111
	 * @return array
112
	 */
113
	protected function getURLs() {
114
		return $this->urls;
115
	}
116
}
117