Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php declare(strict_types=1);
2
/*
3
 * This file is part of sebastian/environment.
4
 *
5
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace SebastianBergmann\Environment;
11
 
12
use const DIRECTORY_SEPARATOR;
13
use const STDIN;
14
use const STDOUT;
15
use function defined;
16
use function fclose;
17
use function fstat;
18
use function function_exists;
19
use function getenv;
20
use function is_resource;
21
use function is_string;
22
use function posix_isatty;
23
use function preg_match;
24
use function proc_close;
25
use function proc_open;
26
use function sapi_windows_vt100_support;
27
use function shell_exec;
28
use function stream_get_contents;
29
use function stream_isatty;
30
use function trim;
31
 
32
final class Console
33
{
34
    /**
35
     * @var int
36
     */
37
    public const STDIN = 0;
38
 
39
    /**
40
     * @var int
41
     */
42
    public const STDOUT = 1;
43
 
44
    /**
45
     * @var int
46
     */
47
    public const STDERR = 2;
48
 
49
    /**
50
     * Returns true if STDOUT supports colorization.
51
     *
52
     * This code has been copied and adapted from
53
     * Symfony\Component\Console\Output\StreamOutput.
54
     */
55
    public function hasColorSupport(): bool
56
    {
57
        if ('Hyper' === getenv('TERM_PROGRAM')) {
58
            return true;
59
        }
60
 
61
        if ($this->isWindows()) {
62
            // @codeCoverageIgnoreStart
63
            return (defined('STDOUT') && function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(STDOUT)) ||
64
                false !== getenv('ANSICON') ||
65
                'ON' === getenv('ConEmuANSI') ||
66
                'xterm' === getenv('TERM');
67
            // @codeCoverageIgnoreEnd
68
        }
69
 
70
        if (!defined('STDOUT')) {
71
            // @codeCoverageIgnoreStart
72
            return false;
73
            // @codeCoverageIgnoreEnd
74
        }
75
 
76
        return $this->isInteractive(STDOUT);
77
    }
78
 
79
    /**
80
     * Returns the number of columns of the terminal.
81
     *
82
     * @codeCoverageIgnore
83
     */
84
    public function getNumberOfColumns(): int
85
    {
86
        if (!$this->isInteractive(defined('STDIN') ? STDIN : self::STDIN)) {
87
            return 80;
88
        }
89
 
90
        if ($this->isWindows()) {
91
            return $this->getNumberOfColumnsWindows();
92
        }
93
 
94
        return $this->getNumberOfColumnsInteractive();
95
    }
96
 
97
    /**
98
     * Returns if the file descriptor is an interactive terminal or not.
99
     *
100
     * Normally, we want to use a resource as a parameter, yet sadly it's not always awailable,
101
     * eg when running code in interactive console (`php -a`), STDIN/STDOUT/STDERR constants are not defined.
102
     *
103
     * @param int|resource $fileDescriptor
104
     */
105
    public function isInteractive($fileDescriptor = self::STDOUT): bool
106
    {
107
        if (is_resource($fileDescriptor)) {
108
            // These functions require a descriptor that is a real resource, not a numeric ID of it
109
            if (function_exists('stream_isatty') && @stream_isatty($fileDescriptor)) {
110
                return true;
111
            }
112
 
113
            // Check if formatted mode is S_IFCHR
114
            if (function_exists('fstat') && @stream_isatty($fileDescriptor)) {
115
                $stat = @fstat(STDOUT);
116
 
117
                return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
118
            }
119
 
120
            return false;
121
        }
122
 
123
        return function_exists('posix_isatty') && @posix_isatty($fileDescriptor);
124
    }
125
 
126
    private function isWindows(): bool
127
    {
128
        return DIRECTORY_SEPARATOR === '\\';
129
    }
130
 
131
    /**
132
     * @codeCoverageIgnore
133
     */
134
    private function getNumberOfColumnsInteractive(): int
135
    {
136
        if (function_exists('shell_exec') && preg_match('#\d+ (\d+)#', shell_exec('stty size') ?: '', $match) === 1) {
137
            if ((int) $match[1] > 0) {
138
                return (int) $match[1];
139
            }
140
        }
141
 
142
        if (function_exists('shell_exec') && preg_match('#columns = (\d+);#', shell_exec('stty') ?: '', $match) === 1) {
143
            if ((int) $match[1] > 0) {
144
                return (int) $match[1];
145
            }
146
        }
147
 
148
        return 80;
149
    }
150
 
151
    /**
152
     * @codeCoverageIgnore
153
     */
154
    private function getNumberOfColumnsWindows(): int
155
    {
156
        $ansicon = getenv('ANSICON');
157
        $columns = 80;
158
 
159
        if (is_string($ansicon) && preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim($ansicon), $matches)) {
160
            $columns = (int) $matches[1];
161
        } elseif (function_exists('proc_open')) {
162
            $process = proc_open(
163
                'mode CON',
164
                [
165
                    1 => ['pipe', 'w'],
166
                    2 => ['pipe', 'w'],
167
                ],
168
                $pipes,
169
                null,
170
                null,
171
                ['suppress_errors' => true]
172
            );
173
 
174
            if (is_resource($process)) {
175
                $info = stream_get_contents($pipes[1]);
176
 
177
                fclose($pipes[1]);
178
                fclose($pipes[2]);
179
                proc_close($process);
180
 
181
                if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
182
                    $columns = (int) $matches[2];
183
                }
184
            }
185
        }
186
 
187
        return $columns - 1;
188
    }
189
}