Completed
Push — master ( 256116...bf8903 )
by personal
04:47
created

Updater::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
/*
4
 * (c) Jean-François Lépine <https://twitter.com/Halleck45>
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Hal\Component\Phar;
11
use Symfony\Component\Console\Helper\ProgressBar;
12
use Symfony\Component\Console\Output\OutputInterface;
13
14
15
/**
16
 * phar updater
17
 *
18
 * @author Jean-François Lépine <https://twitter.com/Halleck45>
19
 */
20
class Updater {
21
22
    const LATEST = 'latest';
23
24
    /**
25
     * @var string
26
     */
27
    private $url = 'https://github.com/Halleck45/PhpMetrics/raw/%s/build/phpmetrics.phar';
28
29
    /**
30
     * @var OutputInterface
31
     */
32
    private $output;
33
34
    /**
35
     * Updater constructor.
36
     * @param $output
37
     */
38
    public function __construct(OutputInterface $output)
39
    {
40
        $this->output = $output;
41
    }
42
43
    /**
44
     * @param string $version
45
     * @return string
46
     */
47
    public function updates($version = self::LATEST) {
48
        $tag = $version;
49
        if(self::LATEST == $version) {
50
            $tag = 'master';
51
        }
52
53
        if (ini_get('phar.readonly') == true) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing ini_get('phar.readonly') of type string to the boolean true. If you are specifically checking for a non-empty string, consider using the more explicit !== '' instead.
Loading history...
54
            throw new \RuntimeException('Unable to update the PHAR, phar.readonly is set, use \'-d phar.readonly=0\'');
55
        }
56
57
        if (ini_get('allow_url_fopen') == false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing ini_get('allow_url_fopen') of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
58
            throw new \RuntimeException('Unable to update the PHAR, allow_url_fopen is not set, use \'-d allow_url_fopen=1\'');
59
        }
60
61
        $currentPharLocation = \Phar::running(false);
62
        if(!file_exists($currentPharLocation) ||strlen($currentPharLocation) == 0) {
63
            throw new \LogicException("You're not currently using Phar. If you have installed PhpMetrics with Composer, please updates it using Composer.");
64
        }
65
66
        if(!is_writable($currentPharLocation)) {
67
            throw new \RuntimeException(sprintf('%s is not writable', $currentPharLocation));
68
        }
69
70
        // downloading
71
        $url = sprintf($this->url, $tag);
72
        $ctx = stream_context_create();
73
        stream_context_set_params($ctx, array("notification" => array($this, 'stream_notification_callback')));
74
        $content = file_get_contents($url, false, $ctx);
75
76
        // replacing file
77
        if(!$content) {
78
            throw new \RuntimeException('Download failed');
79
        }
80
81
        // check if all is OK
82
        $tmpfile = tempnam(sys_get_temp_dir(), 'phar');
83
        file_put_contents($tmpfile, $content);
84
        $output = shell_exec(sprintf('"%s" "%s" --version', PHP_BINARY, $tmpfile));
85
        if(!preg_match('!(v\d+\.\d+\.\d+)!', $output, $matches)) {
86
            throw new \RuntimeException('Phar is corrupted. Please retry');
87
        }
88
89
        // compare versions
90
        $downloadedVersion = $matches[1];
91
        if(self::LATEST !==$version &&$downloadedVersion !== $version) {
92
            throw new \RuntimeException('Incorrect version. Please retry');
93
        }
94
95
        // at this step, all is ok
96
        file_put_contents($currentPharLocation, $content);
97
        return $version;
98
99
    }
100
101
    /**
102
     * Stream downloading
103
     *
104
     * @param $notification_code
105
     * @param $severity
106
     * @param $message
107
     * @param $message_code
108
     * @param $bytes_transferred
109
     * @param $bytes_max
110
     */
111
    public function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
112
        static $filesize = null;
113
        static $progress = null;
114
115
        switch($notification_code) {
116
            case STREAM_NOTIFY_AUTH_REQUIRED:
117
            case STREAM_NOTIFY_AUTH_RESULT:
118
                break;
119
            case STREAM_NOTIFY_CONNECT:
120
                if(!$progress) {
121
                    $this->output->writeln(sprintf("<info>Downloading</info>"));
122
                }
123
                break;
124
125
            case STREAM_NOTIFY_FILE_SIZE_IS:
126
                $filesize = $bytes_max;
127
                $progress = new ProgressBar($this->output);
128
                $progress->start($filesize / 100);
129
                break;
130
131
            case STREAM_NOTIFY_PROGRESS:
132
                if ($bytes_transferred > 0) {
133
                    if (!isset($filesize)) {
134
                        $this->output->writeln(sprintf("<info>Unknown file size.. %2d kb done..</info>", $bytes_transferred/1024));
135
                    } else {
136
                        $progress->setProgress($bytes_transferred / 100);
0 ignored issues
show
Bug introduced by
The method setProgress cannot be called on $progress (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
137
                    }
138
                }
139
                break;
140
141
            case STREAM_NOTIFY_COMPLETED:
142
            case STREAM_NOTIFY_FAILURE:
143
                if($progress) {
144
                    $progress->clear();
145
                    $progress->finish();
146
                }
147
                break;
148
        }
149
    }
150
151
152
}