Passed
Push — release-2.x ( c21d8d...204b60 )
by Slye
01:58
created
src/System.php 1 patch
Indentation   +258 added lines, -258 removed lines patch added patch discarded remove patch
@@ -29,282 +29,282 @@
 block discarded – undo
29 29
  */
30 30
 class System
31 31
 {
32
-    /**
33
-     * @var Dotenv
34
-     */
35
-    private $env;
36
-    /**
37
-     * @var array
38
-     */
39
-    private $errors = [];
40
-    /**
41
-     * @var Lang
42
-     */
43
-    private $l10n;
32
+	/**
33
+	 * @var Dotenv
34
+	 */
35
+	private $env;
36
+	/**
37
+	 * @var array
38
+	 */
39
+	private $errors = [];
40
+	/**
41
+	 * @var Lang
42
+	 */
43
+	private $l10n;
44 44
 
45
-    /**
46
-     * @var System|null
47
-     */
48
-    private static $_instance;
49
-    /**
50
-     * @var AdapterInterface
51
-     */
52
-    private $adapter;
53
-    /**
54
-     * @var string
55
-     */
56
-    private $localDir;
45
+	/**
46
+	 * @var System|null
47
+	 */
48
+	private static $_instance;
49
+	/**
50
+	 * @var AdapterInterface
51
+	 */
52
+	private $adapter;
53
+	/**
54
+	 * @var string
55
+	 */
56
+	private $localDir;
57 57
 
58
-    /**
59
-     * @param AdapterInterface $adapter
60
-     * @param array $adapterOptions
61
-     * @return System|null
62
-     * @throws FileNotFoundException
63
-     * @throws NotAllowedException
64
-     * @throws UnsupportedPHPVersionException
65
-     * @throws \JBZoo\Lang\Exception
66
-     * @throws \JBZoo\Path\Exception
67
-     */
68
-    public static function getInstance(?AdapterInterface $adapter = null, array $adapterOptions = []): ?System
69
-    {
58
+	/**
59
+	 * @param AdapterInterface $adapter
60
+	 * @param array $adapterOptions
61
+	 * @return System|null
62
+	 * @throws FileNotFoundException
63
+	 * @throws NotAllowedException
64
+	 * @throws UnsupportedPHPVersionException
65
+	 * @throws \JBZoo\Lang\Exception
66
+	 * @throws \JBZoo\Path\Exception
67
+	 */
68
+	public static function getInstance(?AdapterInterface $adapter = null, array $adapterOptions = []): ?System
69
+	{
70 70
 
71
-        if (self::$_instance === null) {
72
-            self::$_instance = new System($adapter, $adapterOptions);
73
-        }
74
-        return self::$_instance;
75
-    }
71
+		if (self::$_instance === null) {
72
+			self::$_instance = new System($adapter, $adapterOptions);
73
+		}
74
+		return self::$_instance;
75
+	}
76 76
 
77
-    /**
78
-     * System constructor.
79
-     * @param AdapterInterface|null $adapter
80
-     * @param array $adapterOptions
81
-     * @throws FileNotFoundException
82
-     * @throws \JBZoo\Lang\Exception
83
-     * @throws \JBZoo\Path\Exception
84
-     * @throws UnsupportedPHPVersionException
85
-     * @throws NotAllowedException
86
-     */
87
-    private function __construct(?AdapterInterface $adapter, array $adapterOptions)
88
-    {
89
-        $this->localDir = dirname(__DIR__) . DS;
90
-        $this->loadConfigurationEnvironment();
91
-        $this->l10n = new Lang(env('LANGUAGE', 'en'));
92
-        $this->l10n->load($this->localDir . 'i18n', null, 'yml');
93
-        if (PHP_SAPI !== 'cli' && !(bool)env('ALLOW_EXECUTE_IN_WEB_BROWSER', false)) {
94
-            throw new NotAllowedException($this->l10n->translate('unauthorized_browser'));
95
-        }
96
-        if ((PHP_MAJOR_VERSION . PHP_MINOR_VERSION) < 72) {
97
-            throw new UnsupportedPHPVersionException($this->l10n->translate('unsupported_php_version'));
98
-        }
99
-        if ($adapter === null) {
100
-            $adapter = new Local($this->localDir . env('DIRECTORY_TO_SAVE_LOCAL_BACKUP', 'MySQLBackups') . DS);
101
-        }
102
-        CliFormatter::output($this->l10n->translate('app_started'), CliFormatter::COLOR_BLUE);
103
-        $this->adapter = new Filesystem($adapter, $adapterOptions);
104
-        (int)env('FILES_DAYS_HISTORY', 3) > 0 ? $this->removeOldFilesByIntervalDays() : null;
105
-    }
77
+	/**
78
+	 * System constructor.
79
+	 * @param AdapterInterface|null $adapter
80
+	 * @param array $adapterOptions
81
+	 * @throws FileNotFoundException
82
+	 * @throws \JBZoo\Lang\Exception
83
+	 * @throws \JBZoo\Path\Exception
84
+	 * @throws UnsupportedPHPVersionException
85
+	 * @throws NotAllowedException
86
+	 */
87
+	private function __construct(?AdapterInterface $adapter, array $adapterOptions)
88
+	{
89
+		$this->localDir = dirname(__DIR__) . DS;
90
+		$this->loadConfigurationEnvironment();
91
+		$this->l10n = new Lang(env('LANGUAGE', 'en'));
92
+		$this->l10n->load($this->localDir . 'i18n', null, 'yml');
93
+		if (PHP_SAPI !== 'cli' && !(bool)env('ALLOW_EXECUTE_IN_WEB_BROWSER', false)) {
94
+			throw new NotAllowedException($this->l10n->translate('unauthorized_browser'));
95
+		}
96
+		if ((PHP_MAJOR_VERSION . PHP_MINOR_VERSION) < 72) {
97
+			throw new UnsupportedPHPVersionException($this->l10n->translate('unsupported_php_version'));
98
+		}
99
+		if ($adapter === null) {
100
+			$adapter = new Local($this->localDir . env('DIRECTORY_TO_SAVE_LOCAL_BACKUP', 'MySQLBackups') . DS);
101
+		}
102
+		CliFormatter::output($this->l10n->translate('app_started'), CliFormatter::COLOR_BLUE);
103
+		$this->adapter = new Filesystem($adapter, $adapterOptions);
104
+		(int)env('FILES_DAYS_HISTORY', 3) > 0 ? $this->removeOldFilesByIntervalDays() : null;
105
+	}
106 106
 
107
-    /**
108
-     * Start System initialization
109
-     * @return void
110
-     * @throws RuntimeException
111
-     */
112
-    private function loadConfigurationEnvironment(): void
113
-    {
114
-        if (!file_exists($this->localDir . '.env')) {
115
-            throw new InvalidFileException('Please configure this script with .env file');
116
-        }
117
-        $this->env = Dotenv::create($this->localDir, '.env');
118
-        $this->env->overload();
119
-        $this->checkRequirements();
120
-    }
107
+	/**
108
+	 * Start System initialization
109
+	 * @return void
110
+	 * @throws RuntimeException
111
+	 */
112
+	private function loadConfigurationEnvironment(): void
113
+	{
114
+		if (!file_exists($this->localDir . '.env')) {
115
+			throw new InvalidFileException('Please configure this script with .env file');
116
+		}
117
+		$this->env = Dotenv::create($this->localDir, '.env');
118
+		$this->env->overload();
119
+		$this->checkRequirements();
120
+	}
121 121
 
122
-    /**
123
-     * @return Validator
124
-     */
125
-    private function checkRequirements(): Validator
126
-    {
127
-        return $this->env->required([
128
-            'DB_HOST',
129
-            'DB_USER',
130
-            'DB_PASSWORD'
131
-        ])->notEmpty();
132
-    }
122
+	/**
123
+	 * @return Validator
124
+	 */
125
+	private function checkRequirements(): Validator
126
+	{
127
+		return $this->env->required([
128
+			'DB_HOST',
129
+			'DB_USER',
130
+			'DB_PASSWORD'
131
+		])->notEmpty();
132
+	}
133 133
 
134
-    /**
135
-     * @return array|string
136
-     */
137
-    private function getExcludedDatabases()
138
-    {
139
-        if (empty(trim(env('DB_EXCLUDE_DATABASES', 'information_schema,mysql,performance_schema')))) {
140
-            return [];
141
-        }
142
-        return $this->parseAndSanitize(env('DB_EXCLUDE_DATABASES', 'information_schema,mysql,performance_schema'));
143
-    }
134
+	/**
135
+	 * @return array|string
136
+	 */
137
+	private function getExcludedDatabases()
138
+	{
139
+		if (empty(trim(env('DB_EXCLUDE_DATABASES', 'information_schema,mysql,performance_schema')))) {
140
+			return [];
141
+		}
142
+		return $this->parseAndSanitize(env('DB_EXCLUDE_DATABASES', 'information_schema,mysql,performance_schema'));
143
+	}
144 144
 
145
-    /**
146
-     * @return array
147
-     */
148
-    private function getDatabases(): array
149
-    {
150
-        $pdo = new PDO('mysql:host=' . env('DB_HOST', 'localhost') . ';charset=UTF8', env('DB_USER', 'root'),
151
-            env('DB_PASSWORD', 'root'), [
152
-                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
153
-                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
154
-            ]);
155
-        return $pdo->query('SHOW DATABASES')->fetchAll();
156
-    }
145
+	/**
146
+	 * @return array
147
+	 */
148
+	private function getDatabases(): array
149
+	{
150
+		$pdo = new PDO('mysql:host=' . env('DB_HOST', 'localhost') . ';charset=UTF8', env('DB_USER', 'root'),
151
+			env('DB_PASSWORD', 'root'), [
152
+				PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
153
+				PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
154
+			]);
155
+		return $pdo->query('SHOW DATABASES')->fetchAll();
156
+	}
157 157
 
158
-    /**
159
-     * Process to backup databases
160
-     * @param array $settings
161
-     */
162
-    public function processBackup($settings = []): void
163
-    {
164
-        CliFormatter::output($this->l10n->translate('started_backup'), CliFormatter::COLOR_CYAN);
165
-        $ext = 'sql';
166
-        if (array_key_exists('compress', $settings)) {
167
-            switch ($settings['compress']) {
168
-                case 'gzip':
169
-                case Mysqldump::GZIP:
170
-                    $ext = 'sql.gz';
171
-                    break;
172
-                case 'bzip2':
173
-                case Mysqldump::BZIP2:
174
-                    $ext = 'sql.bz2';
175
-                    break;
176
-                case 'none':
177
-                case Mysqldump::NONE:
178
-                    $ext = 'sql';
179
-                    break;
180
-            }
181
-        }
182
-        foreach ($this->getDatabases() as $database) {
183
-            if (!\in_array($database->Database, $this->getExcludedDatabases(), true)) {
184
-                $filename = $database->Database . '-' . date($this->l10n->translate('date_format')) . ".$ext";
185
-                try {
186
-                    $dumper = new Mysqldump('mysql:host=' . env('DB_HOST',
187
-                            'localhost') . ';dbname=' . $database->Database . ';charset=UTF8',
188
-                        env('DB_USER', 'root'), env('DB_PASSWORD', ''), $settings, [
189
-                            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
190
-                        ]);
191
-                    $tempFile = $this->createTempFile();
192
-                    $dumper->start($tempFile->getRealPath());
193
-                    $this->adapter->writeStream($filename, fopen($tempFile->getRealPath(), 'wb+'));
194
-                    $this->deleteTempFile($tempFile);
195
-                    CliFormatter::output($database->Database . ' ' . $this->l10n->translate('backuped_successfully'),
196
-                        CliFormatter::COLOR_GREEN);
197
-                } catch (Exception $e) {
198
-                    CliFormatter::output('!! ERROR::' . $e->getMessage() . ' !!', CliFormatter::COLOR_RED);
199
-                    $this->errors[] = [
200
-                        'dbname' => $database->Database,
201
-                        'error_message' => $e->getMessage(),
202
-                        'error_code' => $e->getCode()
203
-                    ];
204
-                }
205
-            }
206
-        }
207
-        $this->sendMail();
208
-        CliFormatter::output($this->l10n->translate('databases_backup_successfull'), CliFormatter::COLOR_PURPLE);
209
-    }
158
+	/**
159
+	 * Process to backup databases
160
+	 * @param array $settings
161
+	 */
162
+	public function processBackup($settings = []): void
163
+	{
164
+		CliFormatter::output($this->l10n->translate('started_backup'), CliFormatter::COLOR_CYAN);
165
+		$ext = 'sql';
166
+		if (array_key_exists('compress', $settings)) {
167
+			switch ($settings['compress']) {
168
+				case 'gzip':
169
+				case Mysqldump::GZIP:
170
+					$ext = 'sql.gz';
171
+					break;
172
+				case 'bzip2':
173
+				case Mysqldump::BZIP2:
174
+					$ext = 'sql.bz2';
175
+					break;
176
+				case 'none':
177
+				case Mysqldump::NONE:
178
+					$ext = 'sql';
179
+					break;
180
+			}
181
+		}
182
+		foreach ($this->getDatabases() as $database) {
183
+			if (!\in_array($database->Database, $this->getExcludedDatabases(), true)) {
184
+				$filename = $database->Database . '-' . date($this->l10n->translate('date_format')) . ".$ext";
185
+				try {
186
+					$dumper = new Mysqldump('mysql:host=' . env('DB_HOST',
187
+							'localhost') . ';dbname=' . $database->Database . ';charset=UTF8',
188
+						env('DB_USER', 'root'), env('DB_PASSWORD', ''), $settings, [
189
+							PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
190
+						]);
191
+					$tempFile = $this->createTempFile();
192
+					$dumper->start($tempFile->getRealPath());
193
+					$this->adapter->writeStream($filename, fopen($tempFile->getRealPath(), 'wb+'));
194
+					$this->deleteTempFile($tempFile);
195
+					CliFormatter::output($database->Database . ' ' . $this->l10n->translate('backuped_successfully'),
196
+						CliFormatter::COLOR_GREEN);
197
+				} catch (Exception $e) {
198
+					CliFormatter::output('!! ERROR::' . $e->getMessage() . ' !!', CliFormatter::COLOR_RED);
199
+					$this->errors[] = [
200
+						'dbname' => $database->Database,
201
+						'error_message' => $e->getMessage(),
202
+						'error_code' => $e->getCode()
203
+					];
204
+				}
205
+			}
206
+		}
207
+		$this->sendMail();
208
+		CliFormatter::output($this->l10n->translate('databases_backup_successfull'), CliFormatter::COLOR_PURPLE);
209
+	}
210 210
 
211
-    /**
212
-     * @param string $data
213
-     * @return array|string
214
-     */
215
-    private function parseAndSanitize(string $data)
216
-    {
217
-        $results = explode(',', preg_replace('/\s+/', '', $data));
218
-        if (\count($results) > 1) {
219
-            foreach ($results as $k => $v) {
220
-                $results[$k] = trim($v);
221
-                if (empty($v)) {
222
-                    unset($results[$k]);
223
-                }
224
-            }
225
-            return $results;
226
-        }
227
-        return trim($results[0]);
228
-    }
211
+	/**
212
+	 * @param string $data
213
+	 * @return array|string
214
+	 */
215
+	private function parseAndSanitize(string $data)
216
+	{
217
+		$results = explode(',', preg_replace('/\s+/', '', $data));
218
+		if (\count($results) > 1) {
219
+			foreach ($results as $k => $v) {
220
+				$results[$k] = trim($v);
221
+				if (empty($v)) {
222
+					unset($results[$k]);
223
+				}
224
+			}
225
+			return $results;
226
+		}
227
+		return trim($results[0]);
228
+	}
229 229
 
230
-    /**
231
-     * Send a mail if error or success backup database(s)
232
-     */
233
-    private function sendMail(): void
234
-    {
235
-        $smtpTransport = new Swift_SmtpTransport(env('MAIL_SMTP_HOST', 'localhost'), env('MAIL_SMTP_PORT', 25));
236
-        $smtpTransport->setUsername(env('MAIL_SMTP_USER', ''))->setPassword(env('MAIL_SMTP_PASSWORD', ''));
237
-        $mailer = new Swift_Mailer($smtpTransport);
238
-        if (empty($this->errors)) {
239
-            if ((bool)env('MAIL_SEND_ON_SUCCESS', false)) {
240
-                $body = "<strong>{$this->l10n->translate('mail_db_backup_successfull')}</strong>";
241
-                $message = (new Swift_Message($this->l10n->translate('mail_subject_on_success')))->setFrom(env('MAIL_FROM',
242
-                    '[email protected]'),
243
-                    env('MAIL_FROM_NAME', 'Website Mailer for Database Backup'))
244
-                    ->setTo(env('MAIL_TO'),
245
-                        env('MAIL_TO_NAME', 'Webmaster of my website'))
246
-                    ->setBody($body)
247
-                    ->setCharset('utf-8')
248
-                    ->setContentType('text/html');
249
-                $mailer->send($message);
250
-            }
251
-        } elseif ((bool)env('MAIL_SEND_ON_ERROR', false)) {
252
-            $body = "<strong>{$this->l10n->translate('mail_db_backup_failed')}}:</strong><br><br><ul>";
253
-            foreach ($this->errors as $error) {
254
-                $body .= "<li>
230
+	/**
231
+	 * Send a mail if error or success backup database(s)
232
+	 */
233
+	private function sendMail(): void
234
+	{
235
+		$smtpTransport = new Swift_SmtpTransport(env('MAIL_SMTP_HOST', 'localhost'), env('MAIL_SMTP_PORT', 25));
236
+		$smtpTransport->setUsername(env('MAIL_SMTP_USER', ''))->setPassword(env('MAIL_SMTP_PASSWORD', ''));
237
+		$mailer = new Swift_Mailer($smtpTransport);
238
+		if (empty($this->errors)) {
239
+			if ((bool)env('MAIL_SEND_ON_SUCCESS', false)) {
240
+				$body = "<strong>{$this->l10n->translate('mail_db_backup_successfull')}</strong>";
241
+				$message = (new Swift_Message($this->l10n->translate('mail_subject_on_success')))->setFrom(env('MAIL_FROM',
242
+					'[email protected]'),
243
+					env('MAIL_FROM_NAME', 'Website Mailer for Database Backup'))
244
+					->setTo(env('MAIL_TO'),
245
+						env('MAIL_TO_NAME', 'Webmaster of my website'))
246
+					->setBody($body)
247
+					->setCharset('utf-8')
248
+					->setContentType('text/html');
249
+				$mailer->send($message);
250
+			}
251
+		} elseif ((bool)env('MAIL_SEND_ON_ERROR', false)) {
252
+			$body = "<strong>{$this->l10n->translate('mail_db_backup_failed')}}:</strong><br><br><ul>";
253
+			foreach ($this->errors as $error) {
254
+				$body .= "<li>
255 255
                         <ul>
256 256
                             <li>{$this->l10n->translate('database')}: {$error['dbname']}</li>
257 257
                             <li>{$this->l10n->translate('error_code')}: {$error['error_code']}</li>
258 258
                             <li>{$this->l10n->translate('error_message')}: {$error['error_message']}</li>
259 259
                         </ul>
260 260
                        </li>";
261
-            }
262
-            $body .= '</ul>';
263
-            $message = (new Swift_Message($this->l10n->translate('mail_subject_on_error')))->setFrom(env('MAIL_FROM',
264
-                '[email protected]'),
265
-                env('MAIL_FROM_NAME', 'Website Mailer for Database Backup'))
266
-                ->setTo(env('MAIL_TO'),
267
-                    env('MAIL_TO_NAME', 'Webmaster of my website'))
268
-                ->setBody($body)
269
-                ->setCharset('utf-8')
270
-                ->setContentType('text/html');
271
-            $mailer->send($message);
272
-        }
273
-    }
261
+			}
262
+			$body .= '</ul>';
263
+			$message = (new Swift_Message($this->l10n->translate('mail_subject_on_error')))->setFrom(env('MAIL_FROM',
264
+				'[email protected]'),
265
+				env('MAIL_FROM_NAME', 'Website Mailer for Database Backup'))
266
+				->setTo(env('MAIL_TO'),
267
+					env('MAIL_TO_NAME', 'Webmaster of my website'))
268
+				->setBody($body)
269
+				->setCharset('utf-8')
270
+				->setContentType('text/html');
271
+			$mailer->send($message);
272
+		}
273
+	}
274 274
 
275
-    /**
276
-     * @throws FileNotFoundException
277
-     */
278
-    private function removeOldFilesByIntervalDays(): void
279
-    {
280
-        CliFormatter::output($this->l10n->translate('cleaning_files'), CliFormatter::COLOR_CYAN);
281
-        $files = $this->adapter->listContents();
282
-        foreach ($files as $file) {
283
-            $filetime = $this->adapter->getTimestamp($file['path']);
284
-            $daysInterval = (int)env('FILES_DAYS_HISTORY', 3);
285
-            if ($filetime < strtotime("-{$daysInterval} days")) {
286
-                $this->adapter->delete($file['path']);
287
-            }
288
-        }
289
-        CliFormatter::output($this->l10n->translate('cleaned_files_success'), CliFormatter::COLOR_GREEN);
290
-    }
275
+	/**
276
+	 * @throws FileNotFoundException
277
+	 */
278
+	private function removeOldFilesByIntervalDays(): void
279
+	{
280
+		CliFormatter::output($this->l10n->translate('cleaning_files'), CliFormatter::COLOR_CYAN);
281
+		$files = $this->adapter->listContents();
282
+		foreach ($files as $file) {
283
+			$filetime = $this->adapter->getTimestamp($file['path']);
284
+			$daysInterval = (int)env('FILES_DAYS_HISTORY', 3);
285
+			if ($filetime < strtotime("-{$daysInterval} days")) {
286
+				$this->adapter->delete($file['path']);
287
+			}
288
+		}
289
+		CliFormatter::output($this->l10n->translate('cleaned_files_success'), CliFormatter::COLOR_GREEN);
290
+	}
291 291
 
292
-    /**
293
-     * @return SplFileObject
294
-     */
295
-    private function createTempFile(): SplFileObject
296
-    {
297
-        $file = tmpfile();
298
-        $name = stream_get_meta_data($file)['uri'];
299
-        return new SplFileObject($name, 'w+');
300
-    }
292
+	/**
293
+	 * @return SplFileObject
294
+	 */
295
+	private function createTempFile(): SplFileObject
296
+	{
297
+		$file = tmpfile();
298
+		$name = stream_get_meta_data($file)['uri'];
299
+		return new SplFileObject($name, 'w+');
300
+	}
301 301
 
302
-    /**
303
-     * @param \SplFileInfo $file
304
-     * @return bool
305
-     */
306
-    protected function deleteTempFile(\SplFileInfo $file): bool
307
-    {
308
-        return unlink($file->getRealPath());
309
-    }
302
+	/**
303
+	 * @param \SplFileInfo $file
304
+	 * @return bool
305
+	 */
306
+	protected function deleteTempFile(\SplFileInfo $file): bool
307
+	{
308
+		return unlink($file->getRealPath());
309
+	}
310 310
 }
Please login to merge, or discard this patch.
src/CliFormatter.php 1 patch
Indentation   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -9,31 +9,31 @@
 block discarded – undo
9 9
  */
10 10
 class CliFormatter
11 11
 {
12
-    public const COLOR_BLACK = 30;
13
-    public const COLOR_BLUE = 34;
14
-    public const COLOR_GREEN = 32;
15
-    public const COLOR_CYAN = 36;
16
-    public const COLOR_RED = 31;
17
-    public const COLOR_PURPLE = 35;
18
-    public const COLOR_BROWN = 33;
19
-    public const COLOR_LIGHT_GRAY = 37;
12
+	public const COLOR_BLACK = 30;
13
+	public const COLOR_BLUE = 34;
14
+	public const COLOR_GREEN = 32;
15
+	public const COLOR_CYAN = 36;
16
+	public const COLOR_RED = 31;
17
+	public const COLOR_PURPLE = 35;
18
+	public const COLOR_BROWN = 33;
19
+	public const COLOR_LIGHT_GRAY = 37;
20 20
 
21
-    /**
22
-     * @param string $message
23
-     * @param int|null $color
24
-     */
25
-    public static function output(string $message, int $color = null): void
26
-    {
27
-        if (PHP_SAPI === 'cli') {
28
-            echo ' > ';
29
-            if ($color !== null) {
30
-                echo "\033[{$color}m";
31
-            }
32
-            echo $message;
33
-            if ($color !== null) {
34
-                echo "\033[0m";
35
-            }
36
-            echo PHP_EOL;
37
-        }
38
-    }
21
+	/**
22
+	 * @param string $message
23
+	 * @param int|null $color
24
+	 */
25
+	public static function output(string $message, int $color = null): void
26
+	{
27
+		if (PHP_SAPI === 'cli') {
28
+			echo ' > ';
29
+			if ($color !== null) {
30
+				echo "\033[{$color}m";
31
+			}
32
+			echo $message;
33
+			if ($color !== null) {
34
+				echo "\033[0m";
35
+			}
36
+			echo PHP_EOL;
37
+		}
38
+	}
39 39
 }
40 40
\ No newline at end of file
Please login to merge, or discard this patch.