Everybody knows some computer that was once setup and is not touchable by the end of its life. I had this kind of device. It was a simple macOS app that fetch data from MySQL and send it to the external server. From some reason, it couldn't be done otherwise.
The goal is to run a PHP Script in the Process task on macOS Monterey. To achieve it I made few steps on clear instance:
brew install php
<?php
$servername = "www.example.com";
$username = "login";
$password = "pass";
$dbname = "database";
$port = 12345;
$db = new mysqli($servername, $username, $password, $dbname, $port);
if ($db->connect_error) {
die('Connect Error (' . $db->connect_errno . ') ' . $db->connect_error);
}
$query = $argv[1];
$result = mysqli_query($db, $query);
$db->next_result();
$rows = [];
while($row = $result->fetch_array(MYSQLI_ASSOC)) {
$object = new stdClass();
foreach ($row as $key => $value) {
$object->$key = $value;
}
$rows[] = $object;
}
echo json_encode($rows);
exit;
?>
let outputPipe = Pipe()
let errorPipe = Pipe()
let phpPath = Bundle.main.path(forResource: "Query", ofType: "php")!
let process = Process()
process.launchPath = "/opt/homebrew/Cellar/php/8.1.1/bin/php" //Could be found by using `brew info PHP` in terminal
process.arguments = [phpPath, "call prepared_database_function(null)"]
process.standardOutput = outputPipe
process.standardError = errorPipe
process.terminationHandler = { _ in
let data = outputPipe.fileHandleForReading.readDataToEndOfFile()
print(String(data: data, encoding: .utf8))
let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
print(String(data: errorData, encoding: .utf8))
}
do {
try process.run()
} catch {
print(error)
}
And nothing happens... The problem is that Activity Monitor presents PHP task and I can Force Quit this process. When I will do it terminationHandler
is called and then the output is printed.
How to force a process to end itself, as it is done in a terminal?
I found the solution which is an order of function calls. There is a proper Swift code to run PHP script inside macOS app:
let errorPipe = Pipe()
let outputPipe = Pipe()
let phpPath = Bundle.main.path(forResource: "Query", ofType: "php")!
let process = Foundation.Process()
process.executableURL = URL(fileURLWithPath: "/opt/homebrew/Cellar/php/8.1.1/bin/php") //Could be found by using `brew info php` in terminal
process.arguments = [phpPath, "call prepared_database_function(null)"]
process.standardOutput = outputPipe
process.standardError = errorPipe
do {
try process.run()
} catch {
print(error)
}
let data = outputPipe.fileHandleForReading.readDataToEndOfFile()
let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
process.terminationHandler = { process in
print(String(data: data, encoding: .utf8))
print(String(data: errorData, encoding: .utf8))
}