ProxyPlugin   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 224
Duplicated Lines 0 %

Importance

Changes 9
Bugs 2 Features 1
Metric Value
eloc 74
c 9
b 2
f 1
dl 0
loc 224
rs 10
wmc 21

12 Methods

Rating   Name   Duplication   Size   Complexity  
A uninstall() 0 2 1
A recordProxyEnv() 0 6 3
A getProxyEnvNames() 0 13 1
A getSubscribedEvents() 0 5 1
A getProxyProtocol() 0 5 1
A resetProxyManager() 0 43 1
A activate() 0 6 1
A onPluginPreFileDownload() 0 12 1
A reductionProxyEnv() 0 5 3
A deactivate() 0 2 1
A clearProxyEnv() 0 4 2
A setConfigProxies() 0 15 5
1
<?php
2
3
/*
4
 * This file is part of the Composer Proxy Plugin package.
5
 *
6
 * (c) hugh.li <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace HughCube\Composer\ProxyPlugin;
13
14
use Composer\Composer;
15
use Composer\EventDispatcher\EventSubscriberInterface;
16
use Composer\IO\IOInterface;
17
use Composer\Plugin\PluginEvents;
18
use Composer\Plugin\PluginInterface;
19
use Composer\Plugin\PreFileDownloadEvent;
20
use Composer\Util\Http\ProxyManager;
21
use HughCube\Composer\ProxyPlugin\Config\Config;
22
use HughCube\Composer\ProxyPlugin\Config\ConfigBuilder;
23
use ReflectionClass;
24
use ReflectionException;
25
use Seld\JsonLint\ParsingException;
26
27
/**
28
 * Composer plugin.
29
 *
30
 * @author hugh.li <[email protected]>
31
 */
32
class ProxyPlugin implements PluginInterface, EventSubscriberInterface
33
{
34
    /**
35
     * @var array
36
     */
37
    protected $originProxyEnv = null;
38
39
    /**
40
     * @var Config
41
     */
42
    protected $config;
43
44
    /**
45
     * @var Composer
46
     */
47
    protected $composer;
48
49
    /**
50
     * @var IOInterface
51
     */
52
    protected $io;
53
54
    /**
55
     * @var array
56
     */
57
    protected $reflectionCache = array();
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    public static function getSubscribedEvents()
63
    {
64
        return array(
65
            PluginEvents::PRE_FILE_DOWNLOAD => array(
66
                array('onPluginPreFileDownload', PHP_INT_MIN),
67
            ),
68
        );
69
    }
70
71
    /**
72
     * Get the server proxy name of $_SERVER.
73
     *
74
     * @return array
75
     */
76
    protected function getProxyEnvNames()
77
    {
78
        return array(
79
            'http_proxy',
80
            'HTTP_PROXY',
81
            'CGI_HTTP_PROXY',
82
83
            'https_proxy',
84
            'HTTPS_PROXY',
85
            'CGI_HTTPS_PROXY',
86
87
            'no_proxy',
88
            'NO_PROXY',
89
        );
90
    }
91
92
    /**
93
     * Get the proxy protocol.
94
     *
95
     * @return array
96
     */
97
    protected function getProxyProtocol()
98
    {
99
        return array(
100
            'http' => array('http_proxy', 'HTTP_PROXY', 'CGI_HTTP_PROXY'),
101
            'https' => array('https_proxy', 'HTTPS_PROXY', 'CGI_HTTPS_PROXY'),
102
        );
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     * @throws ParsingException
108
     */
109
    public function activate(Composer $composer, IOInterface $io)
110
    {
111
        $this->io = $io;
112
        $this->config = ConfigBuilder::build($composer, $io);
113
114
        $this->recordProxyEnv();
115
    }
116
117
    /**
118
     * Handling events for downloading files.
119
     *
120
     * @param  PreFileDownloadEvent  $event
121
     * @throws ReflectionException
122
     */
123
    public function onPluginPreFileDownload(PreFileDownloadEvent $event)
124
    {
125
        /** Record the previous value. */
126
        $this->recordProxyEnv();
127
128
        /** Set the current agent based on the configuration. */
129
        $this->setConfigProxies($event->getProcessedUrl());
130
        $this->resetProxyManager($event);
131
132
        /** Restore the previous configuration */
133
        $this->clearProxyEnv();
134
        $this->reductionProxyEnv();
135
    }
136
137
    /**
138
     * @throws ReflectionException
139
     */
140
    protected function resetProxyManager(PreFileDownloadEvent $event)
141
    {
142
        $httpDownloader = $event->getHttpDownloader();
143
144
        $reflection = new ReflectionClass($httpDownloader);
145
        $curlProperty = $reflection->getProperty('curl');
146
        $curlProperty->setAccessible(true);
147
        $curlDownloader = $curlProperty->getValue($httpDownloader);
148
149
        $reflection = new ReflectionClass($curlDownloader);
150
        $proxyManagerProperty = $reflection->getProperty('proxyManager');
151
        $proxyManagerProperty->setAccessible(true);
152
        $proxyManager = $proxyManagerProperty->getValue($curlDownloader);
153
154
        $reflection = new ReflectionClass($proxyManager);
155
156
        /** @see ProxyManager::$fullProxy */
157
        $fullProxyProperty = $reflection->getProperty('fullProxy');
158
        $fullProxyProperty->setAccessible(true);
159
        $fullProxyProperty->setValue($proxyManager, array('http' => null, 'https' => null));
160
161
        /** @see ProxyManager::$safeProxy */
162
        $safeProxyProperty = $reflection->getProperty('safeProxy');
163
        $safeProxyProperty->setAccessible(true);
164
        $safeProxyProperty->setValue($proxyManager, array('http' => null, 'https' => null));
165
166
        /** @see ProxyManager::$streams */
167
        $streamsProperty = $reflection->getProperty('streams');
168
        $streamsProperty->setAccessible(true);
169
        $streamsProperty->setValue(
170
            $proxyManager,
171
            array('http' => array('options' => null), 'https' => array('options' => null))
172
        );
173
174
        /** @see ProxyManager::$hasProxy */
175
        $hasProxyProperty = $reflection->getProperty('hasProxy');
176
        $hasProxyProperty->setAccessible(true);
177
        $hasProxyProperty->setValue($proxyManager, false);
178
179
        /** @see ProxyManager::initProxyData() */
180
        $initProxyDataMethod = $reflection->getMethod('initProxyData');
181
        $initProxyDataMethod->setAccessible(true);
182
        $initProxyDataMethod->invoke($proxyManager);
183
    }
184
185
    /**
186
     * Set up proxies according to configuration.
187
     *
188
     * @param  string  $url
189
     */
190
    protected function setConfigProxies($url)
191
    {
192
        foreach ($this->getProxyProtocol() as $protocol => $names) {
193
            $method = "get{$protocol}Proxy";
194
            if (!method_exists($this->config, $method)) {
195
                continue;
196
            }
197
198
            $proxy = call_user_func(array($this->config, $method), $url);
199
            if (null == $proxy) {
200
                continue;
201
            }
202
203
            foreach ($names as $name) {
204
                $_SERVER[$name] = $proxy;
205
            }
206
        }
207
    }
208
209
    /**
210
     * Record proxy env.
211
     */
212
    protected function recordProxyEnv()
213
    {
214
        $this->originProxyEnv = array();
215
        foreach ($this->getProxyEnvNames() as $name) {
216
            if (array_key_exists($name, $_SERVER)) {
217
                $this->originProxyEnv[$name] = $_SERVER[$name];
218
            }
219
        }
220
    }
221
222
    /**
223
     * Reduction proxy env.
224
     */
225
    protected function reductionProxyEnv()
226
    {
227
        foreach ($this->getProxyEnvNames() as $name) {
228
            if (array_key_exists($name, $this->originProxyEnv)) {
229
                $_SERVER[$name] = $this->originProxyEnv[$name];
230
            }
231
        }
232
    }
233
234
    /**
235
     * clear proxy env.
236
     */
237
    protected function clearProxyEnv()
238
    {
239
        foreach ($this->getProxyEnvNames() as $name) {
240
            unset($_SERVER[$name]);
241
        }
242
    }
243
244
    /**
245
     * @inheritDoc
246
     */
247
    public function deactivate(Composer $composer, IOInterface $io)
248
    {
249
    }
250
251
    /**
252
     * @inheritDoc
253
     */
254
    public function uninstall(Composer $composer, IOInterface $io)
255
    {
256
    }
257
}
258