Bearsampp 2025.8.29
Loading...
Searching...
No Matches
class.batch.php
Go to the documentation of this file.
1<?php
2/*
3 * Copyright (c) 2021-2024 Bearsampp
4 * License: GNU General Public License version 3 or later; see LICENSE.txt
5 * Author: Bear
6 * Website: https://bearsampp.com
7 * Github: https://github.com/Bearsampp
8 */
9
30class Batch
31{
32 const END_PROCESS_STR = 'FINISHED!';
33 const CATCH_OUTPUT_FALSE = 'bearsamppCatchOutputFalse';
34
38 public function __construct()
39 {
40 }
41
47 private static function writeLog($log)
48 {
49 global $bearsamppRoot;
50 Util::logDebug($log, $bearsamppRoot->getBatchLogFilePath());
51 }
52
59 public static function findExeByPid($pid)
60 {
61 $result = self::exec('findExeByPid', 'TASKLIST /FO CSV /NH /FI "PID eq ' . $pid . '"', 5);
62 if ($result !== false) {
63 $expResult = explode('","', $result[0]);
64 if (is_array($expResult) && count($expResult) > 2 && isset($expResult[0]) && !empty($expResult[0])) {
65 return substr($expResult[0], 1);
66 }
67 }
68
69 return false;
70 }
71
78 public static function getProcessUsingPort($port)
79 {
80 $result = self::exec('getProcessUsingPort', 'NETSTAT -aon', 4);
81 if ($result !== false) {
82 foreach ($result as $row) {
83 if (!Util::startWith($row, 'TCP')) {
84 continue;
85 }
86 $rowExp = explode(' ', preg_replace('/\s+/', ' ', $row));
87 if (count($rowExp) == 5 && Util::endWith($rowExp[1], ':' . $port) && $rowExp[3] == 'LISTENING') {
88 $pid = intval($rowExp[4]);
89 $exe = self::findExeByPid($pid);
90 if ($exe !== false) {
91 return $exe . ' (' . $pid . ')';
92 }
93 return $pid;
94 }
95 }
96 }
97
98 return null;
99 }
100
106 public static function exitApp($restart = false)
107 {
109
110 $content = 'PING 1.1.1.1 -n 1 -w 2000 > nul' . PHP_EOL;
111 $content .= '"' . $bearsamppRoot->getExeFilePath() . '" -quit -id={bearsampp}' . PHP_EOL;
112 if ($restart) {
113 $basename = 'restartApp';
114 Util::logInfo('Restart App');
115 $content .= '"' . $bearsamppCore->getPhpExe() . '" "' . Core::isRoot_FILE . '" "' . Action::RESTART . '"' . PHP_EOL;
116 } else {
117 $basename = 'exitApp';
118 Util::logInfo('Exit App');
119 }
120
122 self::execStandalone($basename, $content);
123 }
124
128 public static function restartApp()
129 {
130 self::exitApp(true);
131 }
132
138 public static function getPearVersion()
139 {
140 global $bearsamppBins;
141
142 $result = self::exec('getPearVersion', 'CMD /C "' . $bearsamppBins->getPhp()->getPearExe() . '" -V', 5);
143 if (is_array($result)) {
144 foreach ($result as $row) {
145 if (Util::startWith($row, 'PEAR Version:')) {
146 $expResult = explode(' ', $row);
147 if (count($expResult) == 3) {
148 return trim($expResult[2]);
149 }
150 }
151 }
152 }
153
154 return null;
155 }
156
160 public static function refreshEnvVars()
161 {
163 self::execStandalone('refreshEnvVars', '"' . $bearsamppCore->getSetEnvExe() . '" -a ' . Registry::APP_PATH_REG_ENTRY . ' "' . Util::formatWindowsPath($bearsamppRoot->getRootPath()) . '"');
164 }
165
171 public static function initializeMysql($path)
172 {
173 if (!file_exists($path . '/init.bat')) {
174 Util::logWarning($path . '/init.bat does not exist');
175 return;
176 }
177 self::exec('initializeMysql', 'CMD /C "' . $path . '/init.bat"', 60);
178 }
179
185 public static function installPostgresqlService()
186 {
187 global $bearsamppBins;
188
189 $cmd = '"' . Util::formatWindowsPath($bearsamppBins->getPostgresql()->getCtlExe()) . '" register -N "' . BinPostgresql::SERVICE_NAME . '"';
190 $cmd .= ' -U "LocalSystem" -D "' . Util::formatWindowsPath($bearsamppBins->getPostgresql()->getSymlinkPath()) . '\\data"';
191 $cmd .= ' -l "' . Util::formatWindowsPath($bearsamppBins->getPostgresql()->getErrorLog()) . '" -w';
192 self::exec('installPostgresqlService', $cmd, true, false);
193
194 if (!$bearsamppBins->getPostgresql()->getService()->isInstalled()) {
195 return false;
196 }
197
198 self::setServiceDisplayName(BinPostgresql::SERVICE_NAME, $bearsamppBins->getPostgresql()->getService()->getDisplayName());
199 self::setServiceDescription(BinPostgresql::SERVICE_NAME, $bearsamppBins->getPostgresql()->getService()->getDisplayName());
201
202 return true;
203 }
204
210 public static function uninstallPostgresqlService()
211 {
212 global $bearsamppBins;
213
214 $cmd = '"' . Util::formatWindowsPath($bearsamppBins->getPostgresql()->getCtlExe()) . '" unregister -N "' . BinPostgresql::SERVICE_NAME . '"';
215 $cmd .= ' -l "' . Util::formatWindowsPath($bearsamppBins->getPostgresql()->getErrorLog()) . '" -w';
216 self::exec('uninstallPostgresqlService', $cmd, true, false);
217 return !$bearsamppBins->getPostgresql()->getService()->isInstalled();
218 }
219
225 public static function initializePostgresql($path)
226 {
227 if (!file_exists($path . '/init.bat')) {
228 Util::logWarning($path . '/init.bat does not exist');
229 return;
230 }
231 self::exec('initializePostgresql', 'CMD /C "' . $path . '/init.bat"', 15);
232 }
233
240 public static function createSymlink($src, $dest)
241 {
242 global $bearsamppCore;
243 $src = Util::formatWindowsPath($src);
244 $dest = Util::formatWindowsPath($dest);
245 self::exec('createSymlink', '"' . $bearsamppCore->getLnExe() . '" --absolute --symbolic --traditional --1023safe "' . $src . '" ' . '"' . $dest . '"', true, false);
246 }
247
254 public static function removeSymlink($link)
255 {
256 if (!file_exists($link)) {
257 self::writeLog('-> removeSymlink: Link does not exist: ' . $link);
258 return true; // If the link doesn't exist, nothing to do
259 }
260
261 // Check if it's a directory symlink
262 $isDirectory = is_dir($link);
263 $formattedLink = Util::formatWindowsPath($link);
264
265 try {
266 // Use different commands based on whether it's a directory or file symlink
267 if ($isDirectory) {
268 // For directory symlinks
269 self::exec('removeSymlink', 'rmdir /Q "' . $formattedLink . '"', true, false);
270 } else {
271 // For file symlinks
272 self::exec('removeSymlink', 'del /F /Q "' . $formattedLink . '"', true, false);
273 }
274
275 // Check if removal was successful
276 if (file_exists($link)) {
277 self::writeLog('-> removeSymlink: Failed to remove symlink: ' . $link);
278 return false;
279 }
280
281 self::writeLog('-> removeSymlink: Successfully removed symlink: ' . $link);
282 return true;
283 } catch (Exception $e) {
284 self::writeLog('-> removeSymlink: Exception: ' . $e->getMessage());
285 return false;
286 }
287 }
288
294 public static function getOsInfo()
295 {
296 $result = self::exec('getOsInfo', 'ver', 5);
297 if (is_array($result)) {
298 foreach ($result as $row) {
299 if (Util::startWith($row, 'Microsoft')) {
300 return trim($row);
301 }
302 }
303 }
304 return '';
305 }
306
313 public static function setServiceDisplayName($serviceName, $displayName)
314 {
315 $cmd = 'sc config ' . $serviceName . ' DisplayName= "' . $displayName . '"';
316 self::exec('setServiceDisplayName', $cmd, true, false);
317 }
318
325 public static function setServiceDescription($serviceName, $desc)
326 {
327 $cmd = 'sc description ' . $serviceName . ' "' . $desc . '"';
328 self::exec('setServiceDescription', $cmd, true, false);
329 }
330
337 public static function setServiceStartType($serviceName, $startType)
338 {
339 $cmd = 'sc config ' . $serviceName . ' start= ' . $startType;
340 self::exec('setServiceStartType', $cmd, true, false);
341 }
342
351 public static function execStandalone($basename, $content, $silent = true)
352 {
353 return self::exec($basename, $content, false, false, true, $silent);
354 }
355
368 public static function exec($basename, $content, $timeout = true, $catchOutput = true, $standalone = false, $silent = true, $rebuild = true)
369 {
370 global $bearsamppConfig, $bearsamppWinbinder;
371 $result = false;
372
373 $resultFile = self::getTmpFile('.tmp', $basename);
374 $scriptPath = self::getTmpFile('.bat', $basename);
375 $checkFile = self::getTmpFile('.tmp', $basename);
376
377 // Redirect output
378 if ($catchOutput) {
379 $content .= '> "' . $resultFile . '"' . (!Util::endWith($content, '2') ? ' 2>&1' : '');
380 }
381
382 // Header
383 $header = '@ECHO OFF' . PHP_EOL . PHP_EOL;
384
385 // Footer
386 $footer = PHP_EOL . (!$standalone ? PHP_EOL . 'ECHO ' . self::END_PROCESS_STR . ' > "' . $checkFile . '"' : '');
387
388 // Process
389 file_put_contents($scriptPath, $header . $content . $footer);
390 $bearsamppWinbinder->exec($scriptPath, null, $silent);
391
392 if (!$standalone) {
393 $timeout = is_numeric($timeout) ? $timeout : ($timeout === true ? $bearsamppConfig->getScriptsTimeout() : false);
394 $maxtime = time() + $timeout;
395 $noTimeout = $timeout === false;
396 while ($result === false || empty($result)) {
397 if (file_exists($checkFile)) {
398 $check = file($checkFile);
399 if (!empty($check) && trim($check[0]) == self::END_PROCESS_STR) {
400 if ($catchOutput && file_exists($resultFile)) {
401 $result = file($resultFile);
402 } else {
403 $result = self::CATCH_OUTPUT_FALSE;
404 }
405 }
406 }
407 if ($maxtime < time() && !$noTimeout) {
408 break;
409 }
410 }
411 }
412
413 self::writeLog('Exec:');
414 self::writeLog('-> basename: ' . $basename);
415 self::writeLog('-> content: ' . str_replace(PHP_EOL, ' \\\\ ', $content));
416 self::writeLog('-> checkFile: ' . $checkFile);
417 self::writeLog('-> resultFile: ' . $resultFile);
418 self::writeLog('-> scriptPath: ' . $scriptPath);
419
420 if ($result !== false && !empty($result) && is_array($result)) {
421 if ($rebuild) {
422 $rebuildResult = array();
423 foreach ($result as $row) {
424 $row = trim($row);
425 if (!empty($row)) {
426 $rebuildResult[] = $row;
427 }
428 }
429 $result = $rebuildResult;
430 }
431 self::writeLog('-> result: ' . substr(implode(' \\\\ ', $result), 0, 2048));
432 } else {
433 self::writeLog('-> result: N/A');
434 }
435
436 return $result;
437 }
438
446 private static function getTmpFile($ext, $customName = null)
447 {
448 global $bearsamppCore;
449 return Util::formatWindowsPath($bearsamppCore->getTmpPath() . '/' . (!empty($customName) ? $customName . '-' : '') . Util::random() . $ext);
450 }
451}
$result
global $bearsamppBins
global $bearsamppRoot
$port
global $bearsamppCore
const RESTART
__construct()
static writeLog($log)
static removeSymlink($link)
static installPostgresqlService()
const CATCH_OUTPUT_FALSE
static initializePostgresql($path)
static getProcessUsingPort($port)
static execStandalone($basename, $content, $silent=true)
static setServiceDisplayName($serviceName, $displayName)
static setServiceStartType($serviceName, $startType)
static uninstallPostgresqlService()
static refreshEnvVars()
static initializeMysql($path)
static createSymlink($src, $dest)
static getTmpFile($ext, $customName=null)
static exitApp($restart=false)
static getOsInfo()
static setServiceDescription($serviceName, $desc)
static getPearVersion()
static restartApp()
static exec($basename, $content, $timeout=true, $catchOutput=true, $standalone=false, $silent=true, $rebuild=true)
const END_PROCESS_STR
static findExeByPid($pid)
const isRoot_FILE
const APP_PATH_REG_ENTRY
static logInfo($data, $file=null)
static logDebug($data, $file=null)
static startWith($string, $search)
static random($length=32, $withNumeric=true)
static endWith($string, $search)
static formatWindowsPath($path)
static logWarning($data, $file=null)
static killBins($refreshProcs=false)
global $bearsamppConfig
Definition homepage.php:27