Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | 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
            if (function_exists('stream_isatty') && @stream_isatty($fileDescriptor)) {
109
                return true;
110
            }
111
 
621 lars 112
            if (function_exists('fstat')) {
148 lars 113
                $stat = @fstat(STDOUT);
114
 
621 lars 115
                return $stat && 0020000 === ($stat['mode'] & 0170000);
148 lars 116
            }
117
 
118
            return false;
119
        }
120
 
121
        return function_exists('posix_isatty') && @posix_isatty($fileDescriptor);
122
    }
123
 
124
    private function isWindows(): bool
125
    {
126
        return DIRECTORY_SEPARATOR === '\\';
127
    }
128
 
129
    /**
130
     * @codeCoverageIgnore
131
     */
132
    private function getNumberOfColumnsInteractive(): int
133
    {
134
        if (function_exists('shell_exec') && preg_match('#\d+ (\d+)#', shell_exec('stty size') ?: '', $match) === 1) {
135
            if ((int) $match[1] > 0) {
136
                return (int) $match[1];
137
            }
138
        }
139
 
140
        if (function_exists('shell_exec') && preg_match('#columns = (\d+);#', shell_exec('stty') ?: '', $match) === 1) {
141
            if ((int) $match[1] > 0) {
142
                return (int) $match[1];
143
            }
144
        }
145
 
146
        return 80;
147
    }
148
 
149
    /**
150
     * @codeCoverageIgnore
151
     */
152
    private function getNumberOfColumnsWindows(): int
153
    {
154
        $ansicon = getenv('ANSICON');
155
        $columns = 80;
156
 
157
        if (is_string($ansicon) && preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim($ansicon), $matches)) {
158
            $columns = (int) $matches[1];
159
        } elseif (function_exists('proc_open')) {
160
            $process = proc_open(
161
                'mode CON',
162
                [
163
                    1 => ['pipe', 'w'],
164
                    2 => ['pipe', 'w'],
165
                ],
166
                $pipes,
167
                null,
168
                null,
169
                ['suppress_errors' => true]
170
            );
171
 
172
            if (is_resource($process)) {
173
                $info = stream_get_contents($pipes[1]);
174
 
175
                fclose($pipes[1]);
176
                fclose($pipes[2]);
177
                proc_close($process);
178
 
179
                if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
180
                    $columns = (int) $matches[2];
181
                }
182
            }
183
        }
184
 
185
        return $columns - 1;
186
    }
187
}