Up to Speed with the FileMaker PHP API

So you’ve heard about the new FileMaker PHP API. You want to put FileMaker data on the web, but you’re not sure where to start. It can be a bit overwhelming at first, but using PHP to publish FileMaker to the web is *easy*, *fun*, and *totally awesome*. This (admittedly lengthy) article tells you everything you need to know to get started.

Way back in version 4, FileMaker added built-in web publishing capabilities to FileMaker Pro. With a plug-in called the Web Companion, you could craft custom web pages that pulled data directly from a FileMaker Pro database to stay up-to-date. You could even build entire web sites that were completely managed by a database. This technology was massively popular because it let you publish your FileMaker Pro-based data and services to a broad audience in a form that _anybody_ could handle. The world of FileMaker Web Publishing was born [1](#footnotes), and people loved it.

## It’s the End of the World as We Know It

But this old-school web publishing had a major weakness: it was totally proprietary. As web application development grew in popularity, the importance of standardization also grew. The CDML language used to construct web pages was limited in its capabilities. FileMaker’s built-in web server (which was the only server capable of processing CDML) was anemic. To address these concerns FileMaker introduced a more powerful and standards-compliant web publishing technology with FileMaker Server 7 Advanced: XSLT web publishing. This technology used industry standard Apache and IIS web server software and the open standard XSLT language. Finally you could build fast, capable web pages with fewer limitations, and sill keep a direct connection to your FileMaker Pro database.

Unfortunately, XSLT has its own major weakness: it is __hard__. XSLT is an obtuse, complex, unintuitive language. It is well suited for the standardized transformation of one XML format to another (its primary purpose) but it is a poor fit for web application development. It is an especially bad choice for the FileMaker community, which is largely made up of real honest-to-goodness ordinary folks who don’t have a degree in Computer Science and just want simple tools with which to get the job done.

> I never liked XSLT much. In what I believe is the best computer book ever written (the [Camel Book][1]), the authors outline a primary goal of the Perl programming language. They say “Easy things should be easy, and hard things should be possible.” I tend to think this rule should be applied to any technology you plan to spend your valuable time building with. FileMaker Pro passes this test beautifully, for example. But XSLT does not. In XSLT, even the easiest and most common things are a pain in the rump. But alas, I digress.

[1]: http://www.oreilly.com/catalog/pperl3/ “Programming Perl”

When XSLT replaced CDML back in 2004, web publishing with FileMaker came to a virtual standstill. Instead of the fun, learnable CDML development process, experienced web publishers and new users alike were forced to wade through all the complexities of XSLT and many simply gave up.

## Hope on the Horizon

These days you don’t have to look far to find easy, powerful, standards-based web technologies. For instance, something like 234 trillion people use PHP, a super-capable, super-fast, totally standard web programming language that powers everything from [Wikipedia][2] to [The Roald Dahl Fan Site][3]. Best of all, PHP is infinitely simpler than XSLT. It works the way you would expect: you write some HTML, and add a little code here and there to produce the dynamic parts. [2](#footnotes). Best of all, PHP is well documented on-line ([php.net][8]) and in hundreds of books, magazines, and blogs.

FileMaker noticed that nobody was bothering with XSLT anymore, so they took the plunge and created the FileMaker API for PHP, heretofor called the PHP API. It adds a series of special commands [3](#footnotes) to the PHP language that make it a breeze to talk to your FileMaker database right in your PHP code. This is a big deal. It means that ordinary FileMaker users now have an easy and inexpensive way to get back in to web publishing. I’m looking forward to a second renaissance: FileMaker web publishing will be loved by all again. This article will get you up to speed on the PHP API.

[2]: http://www.wikipedia.com/ “Wikipedia”
[3]: http://www.roalddahlfans.com/ “The Roald Dahl Fan Site”

## Setup and Configuration

Before you can actually start writing code, you need a few critical pieces. They are:

1. _A web server_. Mac OS X users are in luck: the Apache web server is built right in to your computer. If you use Windows, you’ll need a server version with IIS.
2. _The PHP Mojo_. You next need to install PHP and the FileMaker API for PHP on your computer. You can sign up for the public beta [directly from FileMaker][4]. Once you sign up, FileMaker will email you a link to download the software. Unless you are __completely positive you know what you’re doing__ you should choose the “If you are new to PHP” version. This download will install and configure PHP for your computer, and install the API add-ons in just the right spot.
3. _FileMaker Server Advanced_. Like all FileMaker web publishing, the PHP API requires the Web Publishing Engine, which is a part of [FileMaker Server Advanced][5]. Only this (more expensive) version of FileMaker Server has the XML capabilities the PHP API depends on to do its job.

>Update May 9, 2008: I can’t believe I haven’t mentioned this before now, but point #3 above is no longer valid. As of FileMaker Server 9.0, the PHP API can be used with the standard FileMaker Server product, so save some money and don’t bother buying the Advanced version.

Once you have installed and configured the Web Publishing Engine according to [the documentation][6], it will be preconfigured to allow the PHP API to work. If you have modified the configuration, though, you’ll need to log in to the Web Publishing Engine console and make sure Custom Web Publishing with XML is turned on.

This article won’t go in to setting up and configuring web servers. Before you continue, you should have PHP and the FileMaker API for PHP installed and working, and you should know where to put php files so they are accessible by the web server (/Library/WebServer/Documents on Mac OS X, usually C:/inetpub/wwwroot on Windows).

[4]: http://www.filemaker.com/developers/resources/php/index.html “FileMaker PHP download page”
[5]: http://www.filemaker.com/products/fmsa/ “FileMaker Server 8 Advanced”
[6]: http://www.filemaker.com/downloads/documentation/fmsa8_web_install.pdf “FileMaker Web Publishing Engine Installation Guide”

## A Brief Introduction to PHP

If you are new to PHP, this section will attempt to bring you up to speed quickly. But bear in mind that PHP is a vast language with tons of functionality. The ultimate resource is [the php manual][7] at [php.net][8]. Although you’ll get enough info here to make a working PHP web page, you’ll need to do more reading to get really comfortable with the language. On the other hand, if you’re already a php whiz, you can skip right to the next section.

PHP is a template based scripting language. A `.php` file is really just an ordinary text file that tells PHP what kind of text you want to produce. In fact, this is a perfectly valid PHP file:

hello world

If you put a file like that on your web server and view it with a web browser, you’ll see just the words “hello world” on the page. With no special instructions, PHP simply spits out all the text in the file. But that’s not terribly exciting. After all, you could avoid PHP entirely if you just wanted to put some static text on the web page. The magic of PHP comes in to play when you insert these special tags in your page: ``. The things you put between these tags are not simply sent to the browser like plain text. Rather, they are _interpreted_ by the PHP system. You put scripting code between these tags, and PHP runs your scripts. The scripts themselves can output information using the `echo` command. Here is a PHP file with an embedded script:

This script does exactly the same thing as the last one. But it does it by running a snippet of script that uses the `echo` command to put the message on the page. Embedded PHP scripts can do a whole lot more than echo text to the page though. They can perform decision making logic, do math, send email, and (using the FileMaker API for PHP) they can even run a FileMaker script and extract the record data it finds. Here is a PHP file that does a little more:

This sample adds some intelligence to your evolving site. Now it says “good morning world” when the hour of the day is less than 12. It gives a more appropriate “good afternoon world” between noon and 6:00 PM. Finally, after 6 it says “good evening world.” In this sample, you can see some of the basics of the PHP language. First, `$hour` is a variable (all PHP variables start with `$` just like script variables in FileMaker). The line `$hour = date(“G”)` creates the `$hour` variable and sets its value. It uses the `date()` function to find the current hour. You can read more about the date function [here][9]. (In fact, you can get comprehensive documentation on any function in PHP by searching the php web site). In this case, the `”G”` being passed to the `date()` function tells PHP you want just the hours, in 24 hour format.

You can also see PHP’s `if` syntax. The first line checks to see if the `$hour` variable is less than 12. If so, the first `echo` line kicks in. Just like FileMaker’s `If` script step, PHP’s has an `elseif` companion for adding additional conditions. Unfortunately, unlike ScriptMaker, with PHP you have to know what to type: you don’t get a handy point-and-click guide to all the syntax. But with a little patience, exploration of the examples in this article, and some time spent on [php.net][8] or with a good book, you too can be a PHP expert.

[7]: http://www.php.net/manual/en/ “The PHP Manual”
[8]: http://www.php.net/ “The PHP web site”
[9]: http://www.php.net/manual/en/function.date.php “The PHP date function”

## Preparing your Database

Before PHP can talk to your particular database, you need to set up the appropriate privileges. The PHP API looks for its own special extended privilege in FileMaker before it is allowed to do its work. Your job is twofold: define the appropriate extended privilege, and grant that privilege to a privilege set.

1. Open your database in FileMaker Pro.
2. Choose File -> Define -> Accounts & Privileges.
3. Switch to the Extended Privileges tab.
4. Click New.
5. In the Keyword box, enter _fmphp_. You can put anything you want in the Description box, for example _Access via PHP Web Publishing_.
6. Click OK.

Now that the appropriate extended privilege is defined, you need to grant this privilege to some privilege set. Here, you have a decision to make. If your site is going to be available to the public or to lots of users who don’t have accounts in FileMaker, then you should create a _new_ account and a new privilege set. Give the privilege set only the permissions it needs for your web pages to work (including the `fmphp` extended privilege and access to the records and fields that will be used on the web). Then you can hard-code the PHP code to use this username and password. This is the most common method, and the one you’ll use in this article.

On the other hand, if your web users are the same folks who use FileMaker Pro directly, you can give the `fmphp` extended privilege to your existing privilege sets. You’ll also have to use a log in form on your PHP web site to ask for the username and password so FileMaker can connect.

For this article, create a new account with the username `php` and a good password. Assign this account to a new privilege set, called `PHP Access`. When defining the privilege set, follow these steps:

1. In the Records pop-up menu, choose “Create, edit, and delete in all tables.”
2. In the Layouts pop-up menu, choose “All view only.”
3. In the Value Lists pop-up menu, choose “All view only.”
4. In the Scripts pop-up menu, choose “All executable only.”
5. In the Extended Privileges list, turn _off_ “Access via FileMaker Network (fmapp)” and turn _on_ your `fmphp` extended privilege.

When you’re finished setting up privileges, click OK a half-dozen times to dismiss all the open dialog boxes.

## Making the Connection to FileMaker

PHP has thousands of built in functions covering more territory than Lewis and Clark. But one thing it doesn’t have built in is a `connect_to_filemaker_pro()` function. Instead, you use the _classes_ in the PHP API to talk to your FileMaker Pro databases. Before you can do anything with FileMaker, though, you need to make a connection. It is simple:

$connection =& new FileMaker(‘My Database’, ‘myserver’);

This little snippet of PHP code creates a FileMaker object that represents the connection to the database. You pass in the name of your database, and the address of your Web Publishing Engine server. The object is stored in a variable called `$connection` (although you can call this variable anything you want). It is important to note that this command doesn’t actually talk to FileMaker. Instead, it gets _ready_ to talk to FileMaker by storing the appropriate connection information.

The first thing you probably want to do with this object is tell it what username and password to use. You do that thusly:

$connection->setProperty(‘username’, ‘php’);
$connection->setProperty(‘password’, ‘mypassword’);

The object stored in `$connection` has a few _methods_, or built-in functions, that work with the connection. In this case you’re calling the `setProperty` method twice. (You call a method using the _arrow_ operator: `->`. You can see it right between `$connection` and `setProperty`.) First to set the username, and then to set the password. You’ll of course substitute your real password for `mypassword` here.

## Finding and Displaying Record Data

Now the PHP API has all the information it needs to talk to your database. You only need to tell it what to say. The most common thing you’ll do in a PHP page is find some records. You do that with the `newFindCommand` method:

$cmd =& $connection->newFindCommand(‘My Layout’);
$cmd->addFindCriterion(‘First Name’, ‘Sophia’);
$cmd->addFindCriterion(‘Last Name’, ‘Coffey’);
$result = $cmd->execute();

The `newFindCommand` method expects just one parameter, the name of a layout in your database. FileMaker figures out which table to search and which fields to return based on this layout. `newFindCommand` returns a command object, which you store in a variable called `$cmd`.

Before you move on, think hard about what you just did. The fact that you specify a layout for PHP to use raises some important considerations:

– If you remove a field from a layout, that field is no longer sent back to PHP pages that use that layout, even if the field is still in the database. This could break the page.
– If you delete a layout, PHP pages that use it will stop working.
– If you add fields to a layout, the new data will be sent back to PHP pages, although the pages don’t do anything with it. This makes the PHP to FileMaker communication slower without adding any benefit, especially if you add summary fields, complex calculation fields, or large portals.

With these in mind, you’ll understand why it is a good idea to create special layouts specifically for PHP to use. Then you can modify your ordinary layouts without worrying about breaking the pages. And your php-specific layouts can be as trim as possible to keep things running quickly. You could, for example, add a `web_contact` layout to your contact manager database, and include only the fields you want to show on the web.

The second and third lines in this example tell FileMaker what to search for. Using the `addFindCriterion` method, you specify what field to search in, and what value to search for. In this case, you’re asking for records with “Sophia” in the First Name field and “Coffey” in the Last Name field.

The last line calls the `execute` method on the command object. Here, for the first time, the PHP API actually talks to FileMaker. It tells your database to go to the My Layout layout, find all the appropriate records, and send them back. The result (a result object) is stored in the $result variable, ready for you to access.

### Checking for Errors

When you call the `execute` method on a command object, you can actually get one of two possible responses. You _usually_ get a set of records. But you could get an error instead. Errors arise if the Web Publishing Engine isn’t reachable, the layout couldn’t be found, the find criteria was invalid, or simply if no records were found. Before you begin digging for records, then, you need to check for errors. You can make the check easily enough using the `FileMaker::isError` function. You get errors most often when you’re first building a page, as you work out mistakes in your code. When these kinds of errors crop up, it is exceptionally helpful if you get the PHP code to show you information about the error message, so you’re not left wondering what went wrong. So initially, you should use this boilerplate error handling code:

if (FileMaker::isError($result)) {
echo ‘unable to find Sophia Coffey: ‘ . $result->message . ‘(‘ . $result->code . ‘)’;
die();
}

This code checks to see if the result represents an error (notice that your `$result` variable is being sent to the `FileMaker::isError` function). If so, it dumps out a meaningful error message to the page. This message includes the `$result->message` and `$result->code` values, which are the english-language error message numerical code associated with the error. The `die` function tells PHP to stop processing the page. The errors tend to fall in to two categories:

* Sometimes the error will have no code (in parentheses at the very end of the error message). These errors usually mention having trouble communicating with the “host”. This means the PHP API couldn’t talk to your Web Publishing Engine for some reason. Make sure the address is correct, Custom Web Publishing with XML is turned on, your username and password are correct (including case for the password) and that the account has the `fmphp` extended privilege.
* Other errors, which do have a code at the end, are FileMaker errors. FileMaker told the PHP API it couldn’t perform the requested action for some reason. This is almost always because of a typo in your code or some other mistake on your end. For example, if you misspell a field name in your find criteria, you’ll get a Field not Found error. The notable exception is error number 401. This just means no records were found, which may be a reasonable outcome for your web site. You’ll learn how to deal with this particular error shortly.

If you get a FileMaker error code, you should promptly go to Google and search for “FileMaker Error Code X” (only put the real code in place of the X). This will undoubtedly find the page on [briandunning.com][10] where you’ll find a plain-english explanation of the problem. Think about the error you’re getting and see if you can spot where in your code you made a mistake.

The one error code you probably _don’t_ want to show on the web page is FileMakers “No records found” error (401). You can easily enhance your error handling code to deal with this case:

if (FileMaker::isError($result)) {
if ($result->code != 401) {
echo ‘unable to find Sophia Coffey: ‘ . $result->message . ‘(‘ . $result->code . ‘)’;
die();
}
else $notFound = true;
}

This version only sends back an error message (and aborts the page) if the error code is not 401. If you do get a 401 error, it sets a `$notFound` variable to `true` but lets the page continue to process. You’ll use this `$notFound` variable later to avoid asking for records that don’t exist.

[10]: http://www.briandunning.com

### Accessing Record Data

Once you’ve confirmed that you didn’t get an error, you’re ready to look at the records you got back. The result object has a `getRecords` method for just this purpose. It returns a [PHP array][11] of record objects. You can then use the `getField` method on a record object to access actual field data. Here’s an example that puts information from the first record on the page:

$records = $result->getRecords();
echo ‘First Name: ‘ . $records[0]->getField(‘First Name’) . ‘
‘;
echo ‘Last Name: ‘ . $records[0]->getField(‘Last Name’) . ‘
‘;
echo ‘Email Address: ‘ . $records[0]->getField(‘Email Address’) . ‘
‘;

In PHP, arrays start with zero, so the last three lines of this sample use the expression `$records[0]` to fetch the _first_ record. In each case, the `getField` method grabs a field value, which is echo’d onto the page. (The `.` operator in PHP is like FileMaker’s `&` operator: it concatenates text. So each `echo` line here actually prints out a label, then the field value, then an HTML `
` tag.)

More often than not, you want to show _all_ the records instead. To do so, you use a PHP `foreach` loop:

$records = $result->getRecords();
foreach ($records as $record) {
echo ‘First Name: ‘ . $record->getField(‘First Name’) . ‘
‘;
echo ‘Last Name: ‘ . $record->getField(‘Last Name’) . ‘
‘;
echo ‘Email Address: ‘ . $record->getField(‘Email Address’) . ‘
‘;
echo ‘


‘;
}

This time, PHP loops through every record that was found, and puts the name and email information from each one on the page. Notice that inside the `foreach` loop, you have a new variable called `$record` (singular) that holds just one record object, so you no longer need the `[0]` from the previous example.

Using the information you’ve gotten so far, you can do a lot. You could build an entire web site that gets live, up-to-the-minute data right from your database and mixes it right into the web pages. But the PHP API lets you go far beyond just finding data.

[11]: http://www.php.net/manual/en/language.types.array.php “PHP Arrays”

## Other Command Types

In the last section, you used the FileMaker object’s `newFindCommand` to create a command object that finds records. The PHP API has several other methods for additional command types. The more common types are explained here.

> You can also see _all_ the PHP API’s various objects and methods by viewing the “API Docs” that were installed with the API on your web server computer. On Mac OS X, this can be found in /Library/FileMaker Server/Web Publishing/FileMaker API for PHP Docs/apidoc. On Windows, look in C:\Program Files\FileMaker\FileMaker Server\Web Publishing\FileMaker API for PHP Docs\apidocs. In either folder, find the “index.html” file and open it with a web browser.

### Adding New Records

Use the `newAddCommand` to add records to the database. Again, you specify the layout to use. This time, though, you use the `setField` method on the command object to specify the actual field values that should go in the new record.

$cmd = $connection->newAddCommand(‘My Layout’);
$cmd->setField(‘First Name’, ‘Isabel’);
$cmd->setField(‘Last Name’, ‘Coffey’);
$result = $cmd->execute();

Just like with the find command, you need to check for errors after you execute. If all went well, the result object will hold the record that was added. You can inspect this object to see information that was auto-entered, like serial numbers.

### Deleting Records

To delete a record, use the `newDeleteCommand` method. This method expects _two_ parameters. In addition to the layout name, you must provide the record id of the record you want to delete. This is __not__ the value from you ID field or other serial number field. Instead, this is the internal id that FileMaker gives the record without your knowledge. You can find the record id for a record in PHP using the `getRecordId` method on the record object (You can also get a record id from within FileMaker itself using the `Get(RecordId)` fucntion in the Specify Calculation window):

$records = $result->getRecords();
$recordId = $records[0]->getRecordId();

So deleting a record is usually a two-step process. First, you have to _find_ the record you want to delete, so you can ask for its ID. Then you have to _delete_ the record. Here’s an example that shows the whole process:

$cmd = $connection->newFindCommand(‘My Layout’);
$cmd->setField(‘First Name’, ‘Roger’);
$cmd->setField(‘Last Name’, ‘Coffey’);
$result = $cmd->execute();

if (FileMaker::isError($result)) {
echo ‘unable to find the record to delete: ‘ . $result->message . ‘(‘ . $result->code . ‘)’;
die();
}

$records = $result->getRecords();
$recordId = $records[0]->getRecordId();

$cmd = $connection->newDeleteCommand(‘My Layout’, $recordId);
$result = $cmd->execute();

if (FileMaker::isError($result)) {
echo ‘unable to delete the record: ‘ . $result->message . ‘(‘ . $result->code . ‘)’;
die();
}

### Editing Existing Records

Editing a record works a little like adding a record, and a little like deleting. You need to specify the field values just like you did when you added a record. And you need to tell FileMaker which record to edit using a record id, just as with the delete command. Here’s how it works:

$cmd = $connection->newFindCommand(‘My Layout’);
$cmd->setField(‘First Name’, ‘Melinda’);
$cmd->setField(‘Last Name’, ‘Coffey’);
$result = $cmd->execute();

if (FileMaker::isError($result)) {
echo ‘unable to find the record to delete: ‘ . $result->message . ‘(‘ . $result->code . ‘)’;
die();
}

$records = $result->getRecords();
$recordId = $records[0]->getRecordId();

$cmd = $connection->newEditCommand(‘My Layout’, $recordId);
$cmd->setField(‘First Name’, ‘Mamie’);
$result = $cmd->execute();

if (FileMaker::isError($result)) {
echo ‘unable to delete the record: ‘ . $result->message . ‘(‘ . $result->code . ‘)’;
die();
}

This sample finds Melinda Coffey in the database, and changes her first name to Mamie. The result object, if successful, contains the newly edited record.

### Running a Script

No FileMaker API would be complete without the ability to run a FileMaker script. The PHP API makes this a breeze. Just tell it which layout to switch to, which script to run, and (optionally) what parameter to send to the script:

$cmd = $connection->newPerformScriptCommand(‘My Layout’, ‘My Script’, ‘My Parameter’);
$result = $cmd->execute();

As always, you should check the result for errors. If none occurred, the result object will hold all the records that were found after the script finished. If your script doesn’t need a parameter, you can leave that part out entirely, like this:

$cmd = $connection->newPerformScriptCommand(‘My Layout’, ‘My Script’);
$result = $cmd->execute();

### Paging Through Records

Sometimes you have so many records in your database, that it isn’t realistic to put them all on one web page. The find command object has the ability to limit how many records are returned in cases like this. You give the find command a _skip_ value and a _max_ value. For example, if you want the first 100 records, tell it to skip 0 (zero) and include a max of 100. To get the next page-full, perform the same find command again, but this time set the skip to 100. The max should be 100 again. This time FileMaker will give you records 101 through 200. You set these parameters using the `setRange` method on the command object:

$cmd =& $connection->newFindCommand(‘My Layout’);
$cmd->addFindCriterion(‘Last Name’, ‘Coffey’);
$cmd->setRange(0, 100);
$result = $cmd->execute();

In this example, the skip value is 0 and the max value is 100. If you don’t call `setRange`, FileMaker includes _every_ record in the result. For large sets of records, this can be very slow.

## Putting it All Together

In this article you have seen the basic features of the FileMaker API for PHP (stay tuned for another article covering the more advanced features). By combining the various FileMaker commands on several PHP pages, you can build a web site that can interact completely with your FileMaker database, including finding and displaying records, editing them, deleting them, and adding new records. This can come in the form of a straight-forward data management interface (that anyone with a web browser can use) or it can happen behind the scenes while your web users interact with a service-oriented web site.

—-

  1. Truth be told, FileMaker Web Publishing has a history that starts well before the Web Companion in FileMaker 4. But that’s a story for another day.
  2. There are many other fantastic web languages available to pick from. But none of them has the official stamp of approval from FileMaker. PHP is the best choice here simply because FileMaker has done all the hard work to get it to talk to your database.
  3. More correctly, the API is a set of _classes_ for PHP. Like many languages, PHP has a smattering of so-called object-oriented capabilities. FileMaker wrote PHP object types specifically for communicating with a FileMaker Pro database. You can read more about PHP classes in the PHP Manual

Leave a Comment

51 thoughts on “Up to Speed with the FileMaker PHP API

  1. Great article, thanks. I’ve been developing & using FMP (including a static web publishing tool) for well over a decade and have been developing in PHP for 4 years. You do a nice job explaining the marriage.

    A wise decision for FM Inc., to choose PHP. The challenge for me is hosting. I don’t want to host/serve FMP databases. There are thousands of inexpensive (some free), pre-configured PHP hosts out there. Any reliable (and reasonably priced) hosts serving FMP 9?

    I wonder about PHP/mySQL (I favor SQLite) vs. PHP/FMP performance? It would be interesting to see a comparison. My guess is there would be a huge difference (right tool/right job). Still, I think such stats would be interesting. How about a follow up article :).

  2. @eric: For hosting, I can speak personally of Point in Space. We use their PHP and FileMaker hosting and have been happy with the results. Price-wise, FileMaker hosting will always be more expensive than bargain-basement MySQL because it is much more expensive to run FileMaker Servers en masse (since you need license the server software and you’re limited to 125 DBs per server). But I find their pricing very reasonable and their service has been excellent.

    As for performance, MySQL/PHP will outperform FileMaker in most cases. But often, you have a great FileMaker system that just needs some of its data on the web. In a case like that, PHP/FileMaker is a great choice. Truth be told, if I’m building a web site with some database-backed functionality, I would typically not use FileMaker. The performance differences may be very small and may not matter at all in some cases. But if you expect a lot of load, you need to add or update several records at once, or you need a lot of business logic, MySQL can be lots faster.

  3. I need to run Filemaker script through php code.
    I am running following code on my FileMaker Server 9 Advanced.
    *************
    newPerformScriptCommand(‘WebUPIC’, ‘TestScript’);
    $result = $newPerformScript->execute();
    if (FileMaker::isError($result))
    {
    $ErrStr = $result->getErrorString();
    echo “ErrCode: ” . $ErrCode = $result->getCode();

    }
    else
    {
    echo “no error…”;
    }
    ?>
    ************
    Error getting:
    Notice: Only variable references should be returned by reference in C:\Program Files\FileMaker\FileMaker Server\Web Publishing\publishing-engine\php\FileMaker\Command.php on line 126
    no error…
    ************
    Please help/advise to run this code…
    :-)))

  4. I need to run Filemaker script through php code.
    I am running following code on my FileMaker Server 9 Advanced.
    *************
    newPerformScriptCommand(‘WebUPIC’, ‘TestScript’);
    $result = $newPerformScript->execute();
    if (FileMaker::isError($result))
    {
    $ErrStr = $result->getErrorString();
    echo “ErrCode: ” . $ErrCode = $result->getCode();

    }
    else
    {
    echo “no error…”;
    }
    ?>
    ******************
    Error getting:
    Notice: Only variable references should be returned by reference in C:\Program Files\FileMaker\FileMaker Server\Web Publishing\publishing-engine\php\FileMaker\Command.php on line 126
    no error…
    ************
    Please help/advise to run this code…
    :-)))

  5. @trupti:

    I think your problem may be this line:

    echo “ErrCode: ” . $ErrCode = $result->getCode();

    I’m not much of a PHP expert (truthfully I can’t stand the language…). So I’ve never taken the time to learn its rules well, and I’m stabbing in the dark a bit here.

    Anyway, you’re doing a lot in that line. You’re doing an assignment, a method call on an object reference, and a concatenation. I worry that the . operator may bind more tightly than the assignment operator, meaning your code is assigning the result of the method call to the string value that results from this expression:

    "ErrCode: " . $ErrCode

    This is not something you can do, obviously.

    As an aside, in programming languages, expressions can be divided into two forms: so called “l-values” and “r-values”. An l-value is something that can be on the *left* side of an assignment operator. An r-value can only be on the right side. Typically, a variable is a valid l-value, but some static value like 3 or "Hi mom" is not. So in this case, your real problem is an attempt to assign to a non-l-value. That, or something to that effect, is exactly the error you would get in many languages, but not in PHP. But I digress.

    Anyway, you can fix it two ways. First, if you’re hell-bent on keeping it in one line, use parens:

    echo “ErrCode: ” . ($ErrCode = $result->getCode());

    But if it were me, I’d just make it two lines instead:

    $ErrCode = $result->getCode();
    echo “ErrCode: ” . $ErrCode

    I almost always favor slightly more code for the sake of clarity. Put another way, one of my axioms of programing is: “Only be clever when it matters.”

    Hope this helps.

    Geoff

    Edit: As I review this answer, I realize you may not be using the error code anywhere else. In which case, this would also be a valid fix:

    echo “ErrCode: ” . $result->getCode();
  6. I have got the success to run this code.. I have made changes in Command.php file which is located in “C:\Program Files\FileMaker\FileMaker Server\Web Publishing\publishing-engine\php\FileMaker\” folder on Windows server. [i.e. Filemaker server 9 on windows machine.]

    In this file, I have changed function name “@execute” to “execute” and it runs the Filemaker script through PHP command [i.e. newPerformScriptCommand].

  7. In this article it says that when you add a new record, the result object will contain the record that was added. When I add new records using the Filemaker PHP API, the result returned is true. There is no object that I can inspect for the record data. I need to be able to get the order # back that was autogenerated by Filemaker when creating the record and this has been a sticking point for me that nothing online has been able to answer.

    I think I may have found a way to get the data, it seems that it may be somehow getting put back into the query object that I used to query the database and not the result object. This seems very strange to me and I don’t know why it works this way and why your article describes it differently and if I’m likely to run into issues getting the data from the query object. Are others running into this issue?

  8. I’ve solved the mystery (sort of). It turns out that there are two methods for adding a record via Filemaker’s PHP API, one using the createRecord option and a commit, and one using newAddCommand and an execute. Both are described in the PDF that comes with Filemaker 9, and there’s no indication in that PDF file that they are handled differently. But it seems that when you use the execute, you get a Filemaker object result that you can inspect, and when you use commit all you get is a boolean return value. This is why I couldn’t get the data out of my query results. I’m still not sure why the two separate methods exist or why the skimpy documentation doesn’t describe the difference in functionality but at least I know why I couldn’t inspect the result object now.

  9. Re: FX.php, have any SFR readers compared the FMI API to FX.php? I’m not sure that one could offer significant performance increases over the other given that they both essentially communicate with FMS via the XML interface. However, given the availability of a MySQL caching class (FXNeoCache) for FX.php, I think FX.php is certainly worth considering, even for folks new to custom web publishing with Filemaker.

  10. Hello to everybody… There’s a long time that I’m using the FIleMaker… but I started to use the PHP connection with Filemaker only 1 month ago… I learned something but I have a problem that I can’t find a solution… I’d like to put 2 variable ($_phone1 and phone2) inside a field of FM (Phone[2]) and this field have 2 repetitions… How Can I do this?? Sorry for the “errors” of written, because I’m brazilian and my “english” is poor yet… Thank you

  11. @Jozias:

    I’m assuming you have a command object of some kind. For instance:

    $cmd = $connection->newAddCommand('My Layout');

    Normally you do this:

    $cmd.setField("phone", $phone1);

    If you want to set another repetition, you just add a third parameter, like this:

    
    $cmd.setField("phone", $phone1, 1);
    $cmd.setField("phone", $phone2, 2);
    

    The third parameter (1 or 2 in this case) is the repetition number to set. Does that help?

    Geoff

  12. Nice post. I’m a FMP Developper for 8 years now, and Web/Php developper for more than that. Nice article to get right on track.

    Thanks for posting this.

  13. I’m great for the code above Geoff… in the end, I didn’t use two repetitions for the $phone… and now, I have other problem… I’m trying to make a find…

    
    $_busca = $_conexao->newFindCommand('TituloWeb');
    $_busca->addFindCriterion('Titulo', $_conteudoPesquisa);
    $_result = $_busca->execute();
    $_busca2 = $_conexao->newFindCommand('TituloWeb');
    $_busca2->addFindCriterion('Idioma', $_conteudoPesquisa);
    $_result2 = $_busca2->execute();
    busca($_result);// function validate find errors
    $_registros = $_result->getRecords();
    busca($_result2);
    $_registros .= $_result2->getRecords();//the problem it's here
    

    I can’t get the two find command in the $_registros… Can you help me again???

    thank you

    ah… I’m sorry… I liked you website, congrulation!! very good, you’re making a good job!!

  14. In PHP, the .= operator is for appending a string so it simply won’t work for an result object like this.

    You could loop through both sets of records, adding them to a new array. But I think you might be better off just doing one find that gets everything you want. You can do this by adding two find criteria and setting the “logical operator” to or. Here’s the general idea:

    $_busca = $_conexao->newFindCommand('TituloWeb');
    $_busca->addFindCriterion('Titulo', $_conteudoPesquisa);
    $_busca->addFindCriterion('Idioma', $_conteudoPesquisa);
    $_busca->setLogicalOperator(FILEMAKER_FIND_OR);
    $_result = $_busca->execute();
    busca($_result);// function validate find errors
    $_registros = $_result->getRecords();
    

    This code will find records where Titulo contains the search value or where Idioma contains the search value. So your single result should have all the records you want.

    Hope this helps. Tchau!

    Geoff

  15. Hi Goeff,
    i am Filemaker newby and PHP expert. Now i try to follow your advice:You can sign up for the public beta directly from FileMaker. Once you sign up, FileMaker will email you a link to download the softwareit does not work anymore, because Filemaker has withdrawn the PHP Publibeta or I’am blind and cant find the link.
    Perhaps you still have the Windows-Download on some disk and can send it to me.
    To your remark to #3 i fully agree; additionally i think the Filemaker API seems to be the same in FMS9 than in Publicbeta

  16. @donald:

    This article was written before FileMaker 9 was released. You are correct that the public beta is no longer available (and the license precludes me from distributing it). But it is the same API that ships built-right-in with FileMaker Server 9, so if you have 9, you already have it. If you have 8, I’m afraid you’re out of luck. There are other options though, like FX.php.

    And yes, the PHP API built in to 9 (which is the release version of the former public beta) works with any version of FileMaker Server 9, not just the Advanced version.

    Thanks!

    Geoff

  17. I have another question (again… hehehehe)

    I have a db and I want to show the records 10 each page…
    each record has a checkbox… until now it’s right….

    but, if I’m on page 1, and I click in 3 or 4 checkboxes… I go to page 2, when go to page 1 again, a lost the selection of checkboxes…
    I tried to use javascript but I could’t do it…

    Is there solution to this??

    thank you again…
    hugs…

    Jozias

  18. @jozias:

    The trouble is that FileMaker never knows the boxes were checked unless you submit the form in some ways. The simple solution is just to ask your users to click a “Save” button before changing pages, but that is obviously not a very good solution.

    The slickest way to do this is with so-called Ajax. You can set it up so that when they click the checkbox, it immediately saves to the database, which works really well in practice. But it is a little complicated, especially if you are new to Ajax-style web development.

    I don’t have enough space here to do it proper justice, unfortunately. But the gist is that you want to have a javascript “onchange” handler on the checkbox that calls a Javascript function. This function would then formulate a proper PHP page url, and hit it using XMLHttpRequest. To keep things clean, you probably want to disable the checkbox before you hit the server, and then re-enable it once the change is saved. This prevents the user from clicking it repeatedly and causing some problematic race conditions.

    I am a big fan of the Prototype javascript library, which makes all this stuff a lot easier. Assuming you have Prototype in the mix, your javascript function would look roughly like this:

    
    function save_checkbox(field, recordid)
    {
       field.disabled = true;
       new Ajax.Request("save_checkbox.php", {
          parameters: Form.serialize(field.up("FORM")),
          onSuccess: function() {
             field.disabled = false;
          },
          onFailure: function() {
             alert("Could not save checkbox!");
             field.disabled = false;
             field.checked = !field.checked;
          }
       });
    }
    

    On the checkbox end of things, you would need to wrap each checkbox in a form that has the appropriate information for your PHP page (like the record ID). You also add your onchange handler (which in this example uses the “bind” capability from Prototype to easy things up):

    
       <form>
          <input type="hidden" name="record_id" value="...">
          <input type="checkbox" name="check" value="..." onchange="save_checkbox.bind(this);">
       </form>
    

    This code is all “off the top of the head” so it may be a bit wrong, but hopefully it gets you going in the right direction.

    Another nice enhancement is to show a “saving…” type message next to the checkbox while it is being saved so the user knows what is going on. This can be done easily by showing an HTML element in the save_checkbox function, and then hiding it again in the onSuccess and onFailure handlers.

    I know this is all a bit terse, but if you dive in and review the examples from the prototype web site you should be able to get it working very nicely.

    Geoff

  19. Thank you for everything that you helped me until now… but, I have other problem. I wanna get a repetition of a container field, but I can get only if there’s not repetitions, a single field. Is there solution to this problem? I hope so. Since now, thank you.

    Jozias

  20. We are planning to begin using PHP with our Filemaker Pro database however the Filemaker literature says that images cannot be uploaded to containers via their API. Have others found a workaround?

    Mike

  21. Hello
    I am using php api for filemaker.
    In my layout there are fields coming form an ‘external data-source’ another filemaker file it is also on the same filemaker server.
    The extended fmphp user and the relationships are made.
    I can get the data through open remote.
    But through php i do not get the data.

    can anyone give me an idea how can i do this.
    i attach the php file here.
    the direct data of the layout is shown without any problem.
    Only the external data with ::ref,::lang,::label are not shown.

    can anyone help.

    Hope to hear.

    regards,
    antony

    
    session_start();
    require_once 'FileMaker.php';
    $connection =& new FileMaker('GFB_Ftp', 'localhost');
    $connection->setProperty('username', 'php');
    $connection->setProperty('password', 'store');
    
    $connection1 =& new FileMaker('Munutan_struct', 'localhost');
    $connection1->setProperty('username', 'php');
    $connection1->setProperty('password', 'store');
    $cmd1 =& $connection1->newFindCommand('model_Custom_attr');
    $result1 = $cmd1->execute();
    
    $cmd =& $connection->newFindCommand('detail_ftp');
    
    $error_message='';
    
    
    $cmd->addFindCriterion('__ID',">0");
    
    $result = $cmd->execute();
    
    
    if(strlen($error_message)>0)
       {
        echo $error_message;
       }
       else
       {
        //echo 'No records found';// . $result->message . '(' . $result->code . ')';
        }
    
    
    if (FileMaker::isError($result)) {
       
        echo 'No records found';
        echo "Go back";
        die();
    }
    
    if (FileMaker::isError($result)) {
        if ($result->code != 401) {
          echo 'Unable to find klant: ' . $result->message . '(' . $result->code . ')';
          die();
        }
        else $notFound = true;
    }
    $records1 = $result1->getRecords();
    $records = $result->getRecords();
    $res_count=count($records);
    /*echo "search by :".$_GET['zoek_cat'];
    echo "search text :".$_GET['search_text'];*/
    echo "Records found: ".$res_count;
    echo "";
    echo "";
    echo "IDKlantUsernamePasswordRefLangLabel";
    
    $count=0;
    foreach ($records as $record) {
     echo "";
    $cat_item=html_entity_decode($records[$count]->getField('Categorie'),ENT_NOQUOTES,"ISO-8859-1");
    echo "getRecordID()."&web_key=".$records[$count]->getField('web_random_key_klant')."'>".$records[$count]->getField('__ID')."";
    echo "".$records[$count]->getField('klant')."";
    echo "".$records[$count]->getField('userName')."";
    echo "".$records[$count]->getField('passWord')."";
    echo "".$records1[$count]->getField('::ref')."";
    echo "".$records[$count]->getField('::lang')."";
    echo "".$records[$count]>getField('::label')."";
    
    $count++;
    echo "";
    }
    echo "";
    
  22. I made it.
    here is the solution

    
    session_start();
    require_once 'FileMaker.php';
    $connection =& new FileMaker('GFB_Ftp', 'localhost');
    $connection->setProperty('username', 'php');
    $connection->setProperty('password', 'store');
    
    
    $connection1 =& new FileMaker('localhost', 'testfms9.arteprint.be');
    $connection1->setProperty('username', 'php');
    $connection1->setProperty('password', 'store');
    
    $cmd =& $connection->newFindCommand('detail_ftp');
    $cmd1 =& $connection1->newFindCommand('model_Custom_att');
    $error_message='';
    
    
    $cmd->addFindCriterion('__ID',">0");
    
    
    //$cmd->addFindCriterion('Last Name', 'Coffey');
    $result = $cmd->execute();
    
    
    if(strlen($error_message)>0)
       {
        echo $error_message;
       }
       else
       {
        //echo 'No records found';// . $result->message . '(' . $result->code . ')';
        }
    
    
    if (FileMaker::isError($result)) {
       
        echo 'No records found';
        echo "Go back";
        die();
    }
    
    if (FileMaker::isError($result)) {
        if ($result->code != 401) {
          echo 'Unable to find klant: ' . $result->message . '(' . $result->code . ')';
          die();
        }
        else $notFound = true;
    }
    
    $records = $result->getRecords();
    $res_count=count($records);
    /*echo "search by :".$_GET['zoek_cat'];
    echo "search text :".$_GET['search_text'];*/
    echo "Records found: ".$res_count;
    echo "";
    echo "";
    echo "IDKlantUsernamePasswordRefLangLabel";
    
    $count=0;
    foreach ($records as $record) {
     echo "";
    $cat_item=html_entity_decode($records[$count]->getField('Categorie'),ENT_NOQUOTES,"ISO-8859-1");
    echo "getRecordID()."&web_key=".$records[$count]->getField('web_random_key_klant')."'>".$records[$count]->getField('__ID')."";
    echo "".$records[$count]->getField('klant')."";
    echo "".$records[$count]->getField('userName')."";
    echo "".$records[$count]->getField('passWord')."";
    
    $cmd1->addFindCriterion('__ID',$records[$count]->getField('__ID'));
    $result1 = $cmd1->execute();
    $records1 = $result1->getRecords();
    
    foreach ($records1 as $record1) {
    echo "".$record1->getField('ref')."";
    echo "".$record1->getField('lang')."";
    echo "".$record1->getField('label')."";
    }
    /*echo 'Jobnummer: ' . $records[$count]->getField('__Jobnummer') . '';
    echo "Klant getRecordID()."&web_key=".$records[$count]->getField('web_random_key_klant')."'>".($count+1)."";
    echo 'Categorie: ' . $cat_item. '';
    echo 'omschrijving: ' . $records[$count]->getField('Omschrijving') . '';
    echo 'ref_klant_bestelbon: ' . $records[$count]->getField('ref_klant_bestelbon') . '';
    echo 'c_omschrijving_1e_lijn: ' . $records[$count]->getField('c_omschrijving_1e_lijn') . '';
    echo 'record id: ' . $records[$count]->getRecordID() . '';
    echo 'web_random_key_klant: ' . $records[$count]->getField('web_random_key_klant') . '';
    echo 'ref_klant_bestelbon_2: ' . $records[$count]->getField('ref_klant_bestelbon_2') . '';
    echo 'Datum_levering_ingegeven: ' . $records[$count]->getField('Datum_levering_ingegeven') . '';
    echo '';*/
    $count++;
    echo "";
    }
    echo "";
    
  23. Filemaker’s currently pushing itself as an alternative to Excel, which is exactly how we use it, for crunching lots of data. Now we want to display tables of data on the web. The Instant Web Publishing does what we need – simple navigation and nice control over the display of data. But we’re expecting a lot more traffic than the 100 simultaneous connections the server allows. So we’re looking at generating an entirely static website from the Filemaker database. That is, once the website is generated, it consists only of html files and the Filemaker database is not needed at all to serve the pages. (And yes, that means there is zero interactivity). Could we use the PHP site assistant efficiently to do this?

  24. William: I don’t think the PHP Site Assistant will be mush help here, but I may be wrong. It is heavily focused on building an interactive PHP based site for your database.

    I’m not sure how much automation you’re looking for, but you can export FileMaker data to HTML tables, then open the file and clean it up in a tool like DreamWeaver. If you need a more automatic approach, you can use the XML export feature to produce custom HTML from your record data. It is a little complicated at first, but the sky’s the limit with that approach, and the whole thing could be scripted to easily recreate the site as needed.

    Geoff

  25. Hello Geoff… I have a question…

    I’m using the Filemaker.php library to connect with the database…

    the website and the database are in the same host…

    I want to put the website in other host, but I can’t connect with the database…

    The Filemaker.php library should be with the database or with the website?

    I hope you can help me…
    a hug…

    Jozias

  26. Jozias, si eu lembrou corretamente, voce tem que por o fm php no servidor ondo voce tem o database. se voce esta usando fm server advanced, por o api no servidor com filemaker e depois pode ter o php files no servidor outro que tem o website.

  27. Thanks for this page; very helpful.

    I have figured out how to use CWP and PHP to fire off a script in FMP.

    Now I want to call an external script in a second database from that first script that imports the data from the first db. No joy! 8-(

    Is this not possible? Thanks!

  28. We’re running Filemaker Server 9 on a Mac Pro which is not a web server. Our web server is another Mac Pro. The instructions for installing the PHP API look like you’re supposed to install the PHP files on the same server where FMPS is running.

    Can we run the PHP on our web server and use it to query the FMP server? I can’t find any information on this. TIA.

  29. Nickster:

    Sorry for the slow response. Vacation 🙂

    You can absolutely do what you want. You just need to install the PHP API on your web server. There is an independent installer on the FileMaker Server install CD.

    Geoff

  30. Hello,

    I am a filemaker pro developer and I am just exploring the php side. I found your explanation very helpful.
    I am creating a solution that employees can enter their time cards online. The FM solution work fine. It is all related, the employee enters (from a drop down list) his name, project and in a portal his time. This works good. I am trying to make this on the web through php. I cannot find a way to create a related new record with FM and php. Any ideas how it can be done? I can create a new employee, a new project, but I cannot create a new time card entry and relate it to a specific employee and project. Any help would be highly appreciated.

    Regards

  31. hoping that someone’s still watching this … GREAT post!!

    I’m having trouble finding records via my FileMaker PHP interface that include the @ sign. my “email” field, for example, contains a bunch of… email addresses. but when I search that field for, say ‘test@test.com’ (and THAT email address is IN the dB), I get no results.
    if I search for just ‘test’, it returns the proper result.

    I’ve tried urlencode() and decode() and what not but it doesn’t seem to work. or am I just not doing that right?

    any help appreciated!

    =p

  32. hi, coming in late but with an issue:
    I try to perform a find on an email field and even though the email address exists, no records are found. I realized that this might be due to the @ sign in the address. could this be? and what’s the work around?

    thanks!

  33. to answer my question (which I found on some forum).
    @ signs need to be replaced with “\”@\”” (escaped quotes around the @ sign).

  34. Regarding the @ symbol issue when executing a findCommand via the PHP API.

    The correct way to search is to place the whole search string in double quotes (“). E.g. to seach for test@test.com your search string should be:

    $findCommand->addFindCriterion(’email’, ‘”test@test.com”‘);

    Thanks for your original post though Pirco. The post that clarified it for me was here:

    http://forums.filemaker.com/posts/50c48f7295

  35. NIce article., has helped me a bit with error trapping but I do have one problem.

    How would one continue past the error 401?

    I’m using FMStudio(PHP API for fileMaker) for my website and on one page I have several searches with several dynamic tables displaying the reurned records. I’d like the page to continue if there is a 401 on one of the searches but reurn a custom messgae for the search that came up empty.

    I’m not at all well versed with PHP but I imagine the “die” part of the code is basically saying “if no records found for this search – stop processing the page?”

    How can I continue with the other searches?
    Thank you

  36. NIce article., has helped me a bit with error trapping but I do have one problem.

    How would one continue past the error 401?

    I’m using FMStudio(PHP API for fileMaker) for my website and on one page I have several searches with several dynamic tables displaying the reurned records. I’d like the page to continue if there is a 401 on one of the searches but reurn a custom messgae for the search that came up empty.

    I’m not at all well versed with PHP but I imagine the “die” part of the code is basically saying “if no records found for this search – stop processing the page?”

    How can I continue with the other searches?
    Thank you

  37. I did not able to Filemaker.php library file.
    Please help how to include in my program.
    how find Filemaker.php library file?
    waiting for answer.

  38. I’am newbie to filemaker…thanks a lot for this great article to understand the basics of using filemake api…i really enjoyed…thanks a ton again..peace

  39. I don’t buy it that she pays 30%. $60,000 on the tax tables is only 25% bracket. That assumes she has no deductions, credits, or exemptions. If she is married that rate will drop down to around 17%.
    Another example of BS class baiting.

  40. Hi… I am trying to simply trigger an FMP script. I created a run script.php and when I access it, I get and error:

    Notice: Only variable references should be returned by reference in C:\Program Files (x86)\FileMaker\FileMaker Server\Web Publishing\publishing-engine\php\FileMaker\Command.php on line 126

    Here is my code:

    setProperty(‘username’, ‘admin’);
    $connection->setProperty(‘password’, ‘master’);

    $cmd = $connection->newPerformScriptCommand(‘ClassDetail’, ‘web_test’, ‘status’);
    $result = $cmd->execute();

    ?>

  41. Chevell:

    I’m a pretty poor PHP developer but that error means you need an & in there somewhere.

    In your case I think you need it here:

    $cmd = $connection...
    

    Should be…

    $cmd =& $connection...
    

    Does that fix it?