Completed
Push — master ( e81671...a22352 )
by André
93:06 queued 73:42
created

HTTPHandler::validate()   C

Complexity

Conditions 8
Paths 9

Size

Total Lines 39
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 22
nc 9
nop 1
dl 0
loc 39
rs 5.3846
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Bundle\EzPublishCoreBundle\URLChecker\Handler;
8
9
use eZ\Publish\API\Repository\Values\URL\URL;
10
use Symfony\Component\OptionsResolver\OptionsResolver;
11
12
class HTTPHandler extends AbstractURLHandler
13
{
14
    /**
15
     * {@inheritdoc}
16
     *
17
     * Based on https://www.onlineaspect.com/2009/01/26/how-to-use-curl_multi-without-blocking/
18
     */
19
    public function validate(array $urls)
20
    {
21
        if (!$this->options['enabled']) {
22
            return;
23
        }
24
25
        $master = curl_multi_init();
26
        $handlers = [];
27
28
        // Batch size can't be larger then number of urls
29
        $batchSize = min(count($urls), $this->options['batch_size']);
30
        for ($i = 0; $i < $batchSize; ++$i) {
31
            curl_multi_add_handle($master, $this->createCurlHandlerForUrl($urls[$i], $handlers));
32
        }
33
34
        do {
35
            while (($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM);
36
37
            if ($execrun != CURLM_OK) {
38
                break;
39
            }
40
41
            while ($done = curl_multi_info_read($master)) {
42
                $handler = $done['handle'];
43
44
                $this->doValidate($handlers[(int)$handler], $handler);
45
46
                if ($i < count($urls)) {
47
                    curl_multi_add_handle($master, $this->createCurlHandlerForUrl($urls[$i], $handlers));
48
                    ++$i;
49
                }
50
51
                curl_multi_remove_handle($master, $handler);
52
                curl_close($handler);
53
            }
54
        } while ($running);
55
56
        curl_multi_close($master);
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    protected function getOptionsResolver()
63
    {
64
        $resolver = new OptionsResolver();
65
        $resolver->setDefaults([
66
            'enabled' => true,
67
            'timeout' => 10,
68
            'connection_timeout' => 5,
69
            'batch_size' => 10,
70
            'ignore_certificate' => false,
71
        ]);
72
73
        $resolver->setAllowedTypes('enabled', 'bool');
74
        $resolver->setAllowedTypes('timeout', 'int');
75
        $resolver->setAllowedTypes('connection_timeout', 'int');
76
        $resolver->setAllowedTypes('batch_size', 'int');
77
        $resolver->setAllowedTypes('ignore_certificate', 'bool');
78
79
        return $resolver;
80
    }
81
82
    /**
83
     * Initialize and return a cURL session for given URL.
84
     *
85
     * @param URL $url
86
     * @param array $handlers
87
     * @return resource
88
     */
89
    private function createCurlHandlerForUrl(URL $url, array &$handlers)
90
    {
91
        $handler = curl_init();
92
93
        curl_setopt_array($handler, [
94
            CURLOPT_URL => $url->url,
0 ignored issues
show
Documentation introduced by
The property $url is declared protected in eZ\Publish\API\Repository\Values\URL\URL. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
95
            CURLOPT_RETURNTRANSFER => false,
96
            CURLOPT_FOLLOWLOCATION => true,
97
            CURLOPT_CONNECTTIMEOUT => $this->options['connection_timeout'],
98
            CURLOPT_TIMEOUT => $this->options['timeout'],
99
            CURLOPT_FAILONERROR => true,
100
            CURLOPT_NOBODY => true,
101
        ]);
102
103
        if ($this->options['ignore_certificate']) {
104
            curl_setopt_array($handler, [
105
                CURLOPT_SSL_VERIFYPEER => false,
106
                CURLOPT_SSL_VERIFYHOST => false,
107
            ]);
108
        }
109
110
        $handlers[(int)$handler] = $url;
111
112
        return $handler;
113
    }
114
115
    /**
116
     * Validate single response.
117
     *
118
     * @param URL $url
119
     * @param resource $handler CURL handler
120
     */
121
    private function doValidate(URL $url, $handler)
122
    {
123
        $this->setUrlStatus($url, $this->isSuccessful(curl_getinfo($handler, CURLINFO_HTTP_CODE)));
124
    }
125
126
    private function isSuccessful($statusCode)
127
    {
128
        return $statusCode >= 200 && $statusCode < 300;
129
    }
130
}
131