Home > Back-end >  Running PHP script with Foundation Process - Mac OS Monterey - Swift
Running PHP script with Foundation Process - Mac OS Monterey - Swift

Time:01-18

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:

  1. Brew installation - Brew
  2. PHP installation - brew install php
  3. Preparing PHP Script:
<?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;
?>
  1. Prepare Swift code to run PHP Script:
     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)
     }
  1. I am running the program and...

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?

CodePudding user response:

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))
}
  •  Tags:  
  • Related