How to run PHP scripts in Xcode Mac OS X applications

How to run PHP scripts in Xcode Mac OS X applications

Picking a starting point

I spent a lot of time looking around the web for instructions on how to execute PHP scripts in Xcode applilcations only to find a whole lot of nothing. I knew it could be done since there are several apps in the Mac App Store that allow you to interpret PHP on the fly, so I set out to do it without the help I believed I needed. It turns out to be one of the easiest things I’ve done in Objective-C.

There is an update to this post where I’ve done the same thing using modern Swift and incorporated a very basic syntax highlighter.

Swift PHP Runner

The first thing I did was to download the JavaScript Interpreter sample code from the Apple developer site for reference. It’s old code and doesn’t compile readily on a 64 bit system with the OS X Lion SDK, so to get it to run I had to change the target to fit my system as shown below. Xcode will also ask you if you want to update the code to current standards – go ahead and do that.

Screen-Shot-2012-04-19-at-11.11.23-AM How to run PHP scripts in Xcode Mac OS X applications

Getting Objective-C to execute PHP scripts

Screen-Shot-2012-04-19-at-11.11.23-AM How to run PHP scripts in Xcode Mac OS X applications  Screen-Shot-2012-04-19-at-3.41.52-PM How to run PHP scripts in Xcode Mac OS X applications  Next, I changed the code to skip the JavaScript interpreter and use PHP instead. This involves the NSTask Class from the Foundation Framework. Luckily the Foundation Framework is already included in the JSInterpreter sample code. While we’re talking about included Frameworks, you can go ahead and remove the reference to the JavaScript Framework now. To get rid of the red squiggly lines and error messages, delete the #import directive at the top of the MyController.m file along with all of the code inside the evaluateScript method.

Next, I searched for a way to run a command line script similar to “> php testing.php” that would allow me to execute a script and see its output. As always, Stack Overflow came to my rescue. I took the basics of the code there and went to (not very much) work.

First, I had to replace the NSTask LaunchPath with the php binary executable on my system, which is at /usr/bin/php.

Next I had to replace the arguments with the code I wanted to run, which was at ~/tonyj/Sites/harikari/test/testing.php – a script that simply echos “Hello world!” To keep from having to alter the existing code too much, I put in the whole path but left out the filename so that I could type it into the input field of the original application and have it executed when I clicked the button.

That’s it. I built and ran the application and I had a window with an input field and an output filed. I typed the name of my script into the input field and, ta-da!, “Hello world!” appeared in the output field.

A standalone application?

Next I wanted to see if I could make the whole thing a standalone application. This being my first attempt at writing a Mac OS X application in Xcode, I had no idea where to start. So I just went for it. I added my PHP binary to my application (File -> Add Files to JSInterpreter) and then added my script to the project. I wasn’t quite sure what the path was going to be for either of them in the application bundle, so I went back to Stack Overflow to find out about [NSBundle mainBundle] resourcePath] as a method for getting the path to the inside of your application, wherever it may be.

It worked!

With one caveat: I haven’t worked through all of the details yet, so I’m sure there are some dependencies in the PHP binary that my system provides in the place that PHP is looking for them. But I’m confident that it would not be difficult to find and eliminate or compensate for them.

Also, Objective-C doesn’t automatically wait for the return value from a task the way PHP does. And PHP is sometimes a little slow to respond. So you have to figure out how to make it wait around for a response from PHP and your script, especially if it’s a lengthy one. Once again, Stack Overflow helped me find information about the NSNotificationCenter. I don’t know much about it, but it basically notifies your code when the PHP output file is done loading.

Now I can load any PHP script into my application and send and receive messages to and from it. I might try adding MySQL tomorrow.

The code:

Screen-Shot-2012-04-19-at-11.11.23-AM How to run PHP scripts in Xcode Mac OS X applications  Screen-Shot-2012-04-19-at-3.41.52-PM How to run PHP scripts in Xcode Mac OS X applications  forkme_right_darkblue_121621 How to run PHP scripts in Xcode Mac OS X applications

-(NSString *) evaluateScript:(NSString*)scriptName
{
    NSTask *task = [[NSTask alloc] init];
    NSString *taskPath =
        [NSString stringWithFormat:@"%@/%@",
        [[NSBundle mainBundle] resourcePath], @"php"];
    [task setLaunchPath: taskPath];

    NSArray *args;
    NSString* scriptPath =
        [NSString stringWithFormat:@"%@/%@",
        [[NSBundle mainBundle] resourcePath], scriptName];
    NSLog(@"script file path: %@",scriptPath);
    args = [NSArray arrayWithObjects:scriptPath, nil];
    [task setArguments: args];

    NSPipe *pipe = [NSPipe pipe];
    [task setStandardOutput: pipe];

    NSFileHandle *file = [pipe fileHandleForReading];
    [file waitForDataInBackgroundAndNotify];
    [[NSNotificationCenter defaultCenter]
 addObserver:self 
           selector:@selector(receivedData:) 
               name:NSFileHandleDataAvailableNotification 
             object:file];
    [task launch];

    NSData *data = [file readDataToEndOfFile];
    NSString *string =
        [[NSString alloc] initWithData: data
 encoding: NSUTF8StringEncoding];

    return string;
}

- (void)receivedData:(NSNotification *)notif {
    NSFileHandle *file = [notif object];
    NSData *data = [file availableData];
    NSString *str = [[NSString alloc] initWithData:data
 encoding:NSASCIIStringEncoding];
    NSLog(@"%@",str);
}

Altering the code

This is an example of how to type in the name of any file included in your project, but you may want to just execute raw PHP commands or fully integrate PHP into your app. To do this, just look at the line above where the args variable is set. You want your array to have filepath as its first element, then any arguments you want to have available in the argv[] array.

If you want to execute single PHP functions, your first arg will be “-r”, followed by the function as in the following example.

args = [NSArray arrayWithObjects:@"-r",@"is_array(array(1,2,3))", nil];

6 thoughts on “How to run PHP scripts in Xcode Mac OS X applications

  1. Hi,

    i have read your blog entry and that’s exactly what i’m interested in. Is your SourceCode somewhere available for download?

    Thanks,
    Sascha

  2. Hi,

    thank you for your post.
    My problem is, that i could not see the php exec output.

    Do you have an example objc. project?

Leave a Reply

Your email address will not be published. Required fields are marked *