PackagistAdder::execute()   B
last analyzed

Complexity

Conditions 7
Paths 7

Size

Total Lines 43
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 7
eloc 22
c 2
b 0
f 0
nc 7
nop 1
dl 0
loc 43
rs 8.6346
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Thruster\Tool\ProjectGenerator\Console;
6
7
use Symfony\Component\Console\Output\OutputInterface;
8
9
/**
10
 * Class PackagistAdder.
11
 *
12
 * @author  Aurimas Niekis <[email protected]>
13
 */
14
class PackagistAdder
15
{
16
    /** @var string */
17
    private $pauth;
18
19
    /** @var OutputInterface */
20
    private $output;
21
22
    /** @var string */
23
    private $session;
24
25
    public function __construct(string $pauth = null)
26
    {
27
        if (null === $pauth) {
28
            $this->pauth = getenv('PACKAGIST_AUTH');
29
        } else {
30
            $this->pauth = $pauth;
31
        }
32
    }
33
34
    public function execute(OutputInterface $output): int
35
    {
36
        $this->output = $output;
37
38
        if (!$this->pauth) {
39
            $output->writeln('<error>No valid PACKAGIST_AUTH provided!</error>');
40
41
            return 1;
42
        }
43
44
        if (false === $this->checkRequirements()) {
45
            return 1;
46
        }
47
48
        $url = $this->parseConfigFile();
49
        if (false === $url) {
50
            $output->writeln('<error>No valid git remote origins found!</error>');
51
52
            return 1;
53
        }
54
55
        if (false === $this->fetchCSRFToken()) {
56
            $output->writeln('<error>No valid CSRF token found!</error>');
57
58
            return 1;
59
        }
60
61
        if (false === $this->validateUrl($url)) {
62
            $output->writeln('<error>No valid package found in "' . $url . '"</error>');
63
64
            return 1;
65
        }
66
67
        if (false === $this->submitPackage($url)) {
68
            $output->writeln('<error>Error creating package!</error>');
69
70
            return 1;
71
        }
72
73
        $output->writeln('');
74
        $output->writeln('<info>Done.</info>');
75
76
        return 0;
77
    }
78
79
    private function checkRequirements()
80
    {
81
        if (false === file_exists($this->getGitConfigFile())) {
82
            $this->output->writeln(
83
                sprintf(
84
                    '<error>`.git/config` file not found in "%s"</error>',
85
                    getcwd()
86
                )
87
            );
88
89
            return false;
90
        }
91
92
        if (false === file_exists($this->getComposerJsonFile())) {
93
            $this->output->writeln(
94
                sprintf(
95
                    '<error>`composer.json` file not found in "%s"</error>',
96
                    getcwd()
97
                )
98
            );
99
100
            return false;
101
        }
102
103
        return true;
104
    }
105
106
    private function getGitConfigFile(): string
107
    {
108
        return getcwd() . '/.git/config';
109
    }
110
111
    private function getComposerJsonFile(): string
112
    {
113
        return getcwd() . '/composer.json';
114
    }
115
116
    private function parseConfigFile()
117
    {
118
        $file = $this->getGitConfigFile();
119
120
        $ini = parse_ini_file($file, true);
121
122
        foreach ($ini as $group => $config) {
123
            if (0 === strpos($group, 'remote')) {
124
                return $config['url'];
125
            }
126
        }
127
128
        return false;
129
    }
130
131
    private function validateUrl($url): bool
132
    {
133
        $ch = curl_init();
134
135
        curl_setopt($ch, CURLOPT_URL, 'https://packagist.org/packages/fetch-info');
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() 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

135
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_URL, 'https://packagist.org/packages/fetch-info');
Loading history...
136
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
137
138
        $a = 'package[repository]=' . urlencode($url) . '&package[_token]=' . urlencode($this->token);
139
        curl_setopt(
140
            $ch,
141
            CURLOPT_POSTFIELDS,
142
            $a
143
        );
144
        curl_setopt($ch, CURLOPT_POST, 1);
145
146
        $headers   = [];
147
        $headers[] = 'Cookie: pauth=' . $this->pauth . '; packagist=' . $this->session . ';';
148
        $headers[] = 'Origin: https://packagist.org';
149
        $headers[] = 'X-Requested-With: XMLHttpRequest';
150
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
151
152
        $result = curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() 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

152
        $result = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
153
        if (curl_errno($ch)) {
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_errno() 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

153
        if (curl_errno(/** @scrutinizer ignore-type */ $ch)) {
Loading history...
154
            $this->output->writeln(
155
                sprintf(
156
                    '<error>Curl error when trying to validate url "%s"</error>',
157
                    curl_error($ch)
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_error() 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

157
                    curl_error(/** @scrutinizer ignore-type */ $ch)
Loading history...
158
                )
159
            );
160
161
            return false;
162
        }
163
164
        curl_close($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() 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

164
        curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
165
166
        $result = json_decode($result, true);
167
168
        if (JSON_ERROR_NONE !== json_last_error()) {
169
            $this->output->writeln(
170
                sprintf(
171
                    '<error>Error parsing JSON response: %s</error>',
172
                    json_last_error_msg()
173
                )
174
            );
175
176
            return false;
177
        }
178
179
        return 'success' === $result['status'];
180
    }
181
182
    private function submitPackage($url)
183
    {
184
        $ch = curl_init();
185
186
        curl_setopt($ch, CURLOPT_URL, 'https://packagist.org/packages/submit');
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() 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

186
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_URL, 'https://packagist.org/packages/submit');
Loading history...
187
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
188
189
        $a = 'package[repository]=' . urlencode($url) . '&package[_token]=' . urlencode($this->token);
190
        curl_setopt(
191
            $ch,
192
            CURLOPT_POSTFIELDS,
193
            $a
194
        );
195
        curl_setopt($ch, CURLOPT_POST, 1);
196
197
        $headers   = [];
198
        $headers[] = 'Cookie: pauth=' . $this->pauth . '; packagist=' . $this->session . ';';
199
        $headers[] = 'Origin: https://packagist.org';
200
        $headers[] = 'X-Requested-With: XMLHttpRequest';
201
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
202
        curl_setopt($ch, CURLOPT_HEADER, 1);
203
204
        $result = curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() 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

204
        $result = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
205
        if (curl_errno($ch)) {
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_errno() 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

205
        if (curl_errno(/** @scrutinizer ignore-type */ $ch)) {
Loading history...
206
            $this->output->writeln(
207
                sprintf(
208
                    '<error>Curl error when trying to validate url "%s"</error>',
209
                    curl_error($ch)
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_error() 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

209
                    curl_error(/** @scrutinizer ignore-type */ $ch)
Loading history...
210
                )
211
            );
212
213
            return false;
214
        }
215
216
        curl_close($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() 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

216
        curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
217
218
        $line = strtok($result, "\n");
219
220
        return false !== strpos($line, '302');
221
    }
222
223
    private function fetchCSRFToken()
224
    {
225
        $ch = curl_init();
226
227
        curl_setopt($ch, CURLOPT_URL, 'https://packagist.org/packages/submit');
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() 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

227
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_URL, 'https://packagist.org/packages/submit');
Loading history...
228
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
229
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
230
231
        $headers   = [];
232
        $headers[] = 'Cookie: pauth=' . $this->pauth . ';';
233
        $headers[] = 'Origin: https://packagist.org';
234
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
235
        curl_setopt($ch, CURLOPT_HEADER, 1);
236
237
        $result = curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() 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

237
        $result = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
238
        if (curl_errno($ch)) {
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_errno() 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

238
        if (curl_errno(/** @scrutinizer ignore-type */ $ch)) {
Loading history...
239
            $this->output->writeln(
240
                sprintf(
241
                    '<error>Curl error when trying to fetch CSRF token "%s"</error>',
242
                    curl_error($ch)
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_error() 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

242
                    curl_error(/** @scrutinizer ignore-type */ $ch)
Loading history...
243
                )
244
            );
245
246
            return false;
247
        }
248
249
        curl_close($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() 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

249
        curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
250
251
        if (preg_match('/packagist=([^;]+)/', $result, $matches)) {
252
            $this->session = $matches[1];
253
        } else {
254
            return false;
255
        }
256
257
        if (preg_match('/name="package\[_token\]" class=" form-control" value="([^"]+)"/', $result, $matches)) {
258
            $this->token = $matches[1];
0 ignored issues
show
Bug Best Practice introduced by
The property token does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
259
260
            return true;
261
        } else {
262
            return false;
263
        }
264
    }
265
}
266