サンプルデータの作成は FileMaker Data API を使う 2025 年版 vol.1 を参照してください。
利用環境
以下の環境を前提に説明しています。
- Claris FileMaker Pro 21.1.1.41 macOS
- Claris FileMaker Server 21.1.1.40 Ubuntu 22(AMD)
- サーバ: Ubuntu 22.04.5 LTS
- SSL 証明書
- リクエストする側のサーバ(任意)
開発段階では、以下を使用した方が楽でしょう。
filemaker-data-api-v2.1.php
<?php
class FileMaker_Data_API
{
public $host, $version, $database, $username, $password, $layout;
public $bearer_session_token;
function __construct (string $host, string $version)
{
$this->host = $host;
$this->version = $version;
}
/**
* リクエスト
**/
// ログイン
public function login (string $database, string $username, string $password): string
{
$this->database = $database;
$this->username = $username;
$this->password = $password;
$auth_value = $username . ':' . $password;
$authorization = 'Authorization: Basic ' . base64_encode($auth_value);
$content_type = 'Content-Type: application/json';
$curlopt_httpheader = array($authorization, $content_type);
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/sessions";
return self::executeCurl($endpoint, 'POST', $curlopt_httpheader);
}
// ログアウト
public function logOut(string $database, string $bearer_session_token): string
{
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/sessions/{$bearer_session_token}";
return self::executeCurl($endpoint, 'DELETE');
}
// データベースセッションの検証
public function validateSession (string $session_token): string
{
$authorization = 'Authorization: Bearer ' . $session_token;
$curlopt_httpheader = array($authorization);
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/validateSession";
return self::executeCurl($endpoint, 'GET', $curlopt_httpheader);
}
// レコード範囲の取得
public function getRecords(
string $database,
string $layout,
string $bearer_session_token,
array &$script_name_array,
array &$script_param_array,
int $_offset = 1,
int $_limit = 100,
string $_sort = ''
): string
{
$this->layout = $layout;
$authorization = 'Authorization: Bearer ' . $bearer_session_token;
$curlopt_httpheader = array($authorization);
// ソートの設定
$_sort_string = !empty($_sort) ? '&_sort=' . urlencode($_sort) : '';
$script_prerequest = '';
$script_prerequest_param = '';
$script_presort = '';
$script_presort_param = '';
$script = '';
$script_param = '';
// リクエスト処理前のスクリプト
if ($script_name_array[0] !== '') {
$script_prerequest = '&script.prerequest=' . $script_name_array[0];
$script_prerequest_param = '&script.prerequest.param=' . urlencode(json_encode($script_param_array[0]));
}
// ソート前のスクリプト
if ($script_name_array[1] !== '') {
$script_presort = '&script.presort=' . $script_name_array[1];
$script_presort_param = '&script.presort.param=' . urlencode(json_encode($script_param_array[1]));
}
// リクエスト処理後のスクリプト
if ($script_name_array[2] !== '') {
$script = '&script=' . $script_name_array[2];
$script_param = '&script.param=' . urlencode(json_encode($script_param_array[2]));
}
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/layouts/{$layout}/records?_offset={$_offset}&_limit={$_limit}{$_sort_string}{$script_prerequest}{$script_prerequest_param}{$script_presort}{$script_presort_param}{$script}{$script_param}";
return self::executeCurl($endpoint, 'GET', $curlopt_httpheader);
}
/**
* ユーティリティ
**/
// レスポンスコードの取得
public function getMessagesCode (string $response): string
{
$response_array = self::json2array($response);
return $response_array['messages'][0]['code'];
}
// Bearer Session Token 取得
public function getBearerSessionToken (string $response): string
{
$response_array = self::json2array($response);
$this->bearer_session_token = $response_array['response']['token'];
return $this->bearer_session_token;
}
// JSON を 配列へ変換
public function json2array (string $json): array
{
$json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
return json_decode($json, true);
}
// cURL 実行
static function executeCurl(string $curlopt_url, string $curlopt_customrequest, array $curlopt_httpheader = []): string
{
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $curlopt_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $curlopt_customrequest,
CURLOPT_HTTPHEADER => $curlopt_httpheader,
CURLOPT_POSTFIELDS => "{}",
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
}
Find Records
前回まで、records - Get Records を使用してレコードを取得していましたが、今回は、records - Find Records を使用して同じことをやってみたいと思います。
Get Records と Find Records の顕著な違いは、リクエストメソッドが GET
か POST
かということにあります。GET
である Get Records では、クエリパラメータを URL の一部として渡していました。Find Records は、POST
なので、URL でクエリパラメータを渡すということはありません。
Find Records では、JSON形式で、リクエストボディを作り、ポストフィールドとして渡します。
渡せるクエリパラメータは、ほとんど Get Records と同じです。但し、すべてを JSON 形式で渡すということになります。
では、まず、filemaker-data-api-v2.1.php に findRecords()
メソッドを getRecords()
メソッドの下に追加します。
// 検索の実行
public function findRecords(
string $database,
string $layout,
string $bearer_session_token,
string $request_body
): string
{
$authorization = 'Authorization: Bearer ' . $bearer_session_token;
$content_type = 'Content-Type: application/json';
$curlopt_httpheader = array($authorization, $content_type);
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/layouts/{$layout}/_find";
return self::executeCurl($endpoint, 'POST', $curlopt_httpheader, $request_body);
}
さらに、executeCurl()
メソッドもアップデートして、ファイル名を filemaker-data-api-v2.2.php
とします。
// cURL 実行
static function executeCurl(string $curlopt_url, string $curlopt_customrequest, array $curlopt_httpheader = [], string $current_postfields = ''): string
{
$current_postfields = !empty($current_postfields) ? json_encode(json_decode($current_postfields)) : '{}';
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $curlopt_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $curlopt_customrequest,
CURLOPT_POSTFIELDS => $current_postfields,
CURLOPT_HTTPHEADER => $curlopt_httpheader,
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
メインプログラムも、ほとんど変わりませんが、クエリパラメータの作成が大変、楽になります。
find_records.php
<?php
require_once(__DIR__ . '/filemaker-data-api-v2.2.php');
$host = 'FileMaker Server ドメイン名';
$version = 'vLatest';
$database = 'FileMaker ソリューション名';
$username = 'FileMaker ユーザ名';
$password = 'パスワード';
$layout = 'player_batting_basic';
$bearer_session_token = null;
$fmda = new FileMaker_Data_API($host, $version);
// ログイン
$response = $fmda->login($database, $username, $password);
// ログイン成功?
if ($fmda->getMessagesCode($response) === '0') {
// ログイン成功なら、Bearer Session Token を取得する
$bearer_session_token = $fmda->getBearerSessionToken($response);
} else {
// ログイン失敗の処理を書く
echo "FileMaker Data API へのログインに失敗しました。\n";
}
// (何らかの処理があり、リンクでページ遷移した想定)
// セッションの検証
$response = $fmda->validateSession($bearer_session_token);
if ($fmda->getMessagesCode($response) === '0') {
// セッション有効なら、行いたいリクエスト実行
$request_body = <<<_JSON_
{
"query" :
[
{
"year" : "2024",
"omit" : "false"
}
],
"sort" :
[
{
"fieldName" : "on_base_percent",
"sortOrder" : "descend"
}
],
"offset" : "1",
"limit" : "10"
}
_JSON_;
// レコードの検索
$response = $fmda->findRecords($database, $layout, $bearer_session_token, $request_body);
// 結果セット処理
$result = $fmda->json2array($response);
if ($fmda->getMessagesCode($response) === '0') {
$player_data = $result['response']['data'];
foreach ($player_data as $key => $value) {
echo $value['fieldData']['last_name_ first_name'] . ' - ';
echo $value['fieldData']['on_base_percent'], PHP_EOL;
}
}
echo "総レコード数: {$result['response']['dataInfo']['totalRecordCount']}\n";
echo "現在レコード数: {$result['response']['dataInfo']['foundCount']}\n";
echo "取得レコード数: {$result['response']['dataInfo']['returnedCount']}\n";
} else {
// セッション無効なら、必要な Web データを保持して、ユーザに再ログインを促す
echo "再ログインしてください。\n";
}
// (何らかの処理)
// ログアウト
$response = $fmda->logOut($database, $bearer_session_token);
リクエストメソッドが POST
の場合、ポストフィールドに JSON をそのまま渡せばいいので、ソースコード内に JSON をハードコードしています。
このままでは、空白、改行が沢山含まれてしまうので、一旦、配列にして、それをまた JSON に戻すという処理を入れて、一気に、空白文字を削除しています。正規表現を使うよりシンプルに変換できると思います。
JSON を外部ファイルとして持てば、条件に応じて結果セットを変えるという応用もできるでしょう。
Get Records では、2024年の選手データに絞り込むためにスクリプトを使用しましたが、Find Records では、キー query
の中に、次の形式で、条件を設定していくだけで、同じことが実現できます。
"query" :
[
{
"フィールド名" : "検索する値",
"omit" : "false"
},
{
"フィールド名r" : "検索する値",
"omit" : "false"
}
]
この キー query
はFind Records リクエストでは必須です。
キー omit
は、除外検索のフラグになっています。true
とすれば、除外検索になります。
スクリプトも、次の形式で JSON に追加すれば指定できます。
"script.prerequest" : "リクエスト処理前に実行するスクリプト名",
"script.prerequest.param" : "リクエスト処理前に実行するスクリプトの引数",
"script.presort" : "ソート実行前に実行するスクリプト名",
"script.presort.param" : "ソート実行前に実行するスクリプトの引数",
"script" : "リクエスト処理後に実行するスクリプト名",
"script.param" : "リクエスト処理後に実行するスクリプトの引数"
考え方は、Get Records のスクリプト指定と同じです。
完成版 filemaker-data-api-v2.2.php
<?php
class FileMaker_Data_API
{
public $host, $version, $database, $username, $password, $layout;
public $bearer_session_token;
function __construct (string $host, string $version)
{
$this->host = $host;
$this->version = $version;
}
/**
* リクエスト
**/
// ログイン
public function login (string $database, string $username, string $password): string
{
$this->database = $database;
$this->username = $username;
$this->password = $password;
$auth_value = $username . ':' . $password;
$authorization = 'Authorization: Basic ' . base64_encode($auth_value);
$content_type = 'Content-Type: application/json';
$curlopt_httpheader = array($authorization, $content_type);
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/sessions";
return self::executeCurl($endpoint, 'POST', $curlopt_httpheader);
}
// ログアウト
public function logOut(string $database, string $bearer_session_token): string
{
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/sessions/{$bearer_session_token}";
return self::executeCurl($endpoint, 'DELETE');
}
// データベースセッションの検証
public function validateSession (string $session_token): string
{
$authorization = 'Authorization: Bearer ' . $session_token;
$curlopt_httpheader = array($authorization);
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/validateSession";
return self::executeCurl($endpoint, 'GET', $curlopt_httpheader);
}
// レコード範囲の取得
public function getRecords(
string $database,
string $layout,
string $bearer_session_token,
array &$script_name_array,
array &$script_param_array,
int $_offset = 1,
int $_limit = 100,
string $_sort = ''
): string
{
$this->layout = $layout;
$authorization = 'Authorization: Bearer ' . $bearer_session_token;
$curlopt_httpheader = array($authorization);
// ソートの設定
$_sort_string = !empty($_sort) ? '&_sort=' . urlencode($_sort) : '';
$script_prerequest = '';
$script_prerequest_param = '';
$script_presort = '';
$script_presort_param = '';
$script = '';
$script_param = '';
// リクエスト処理前のスクリプト
if ($script_name_array[0] !== '') {
$script_prerequest = '&script.prerequest=' . $script_name_array[0];
$script_prerequest_param = '&script.prerequest.param=' . urlencode(json_encode($script_param_array[0]));
}
// ソート前のスクリプト
if ($script_name_array[1] !== '') {
$script_presort = '&script.presort=' . $script_name_array[1];
$script_presort_param = '&script.presort.param=' . urlencode(json_encode($script_param_array[1]));
}
// リクエスト処理後のスクリプト
if ($script_name_array[2] !== '') {
$script = '&script=' . $script_name_array[2];
$script_param = '&script.param=' . urlencode(json_encode($script_param_array[2]));
}
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/layouts/{$layout}/records?_offset={$_offset}&_limit={$_limit}{$_sort_string}{$script_prerequest}{$script_prerequest_param}{$script_presort}{$script_presort_param}{$script}{$script_param}";
return self::executeCurl($endpoint, 'GET', $curlopt_httpheader);
}
// 検索の実行
public function findRecords(
string $database,
string $layout,
string $bearer_session_token,
string $request_body
): string
{
$authorization = 'Authorization: Bearer ' . $bearer_session_token;
$content_type = 'Content-Type: application/json';
$curlopt_httpheader = array($authorization, $content_type);
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/layouts/{$layout}/_find";
return self::executeCurl($endpoint, 'POST', $curlopt_httpheader, $request_body);
}
/**
* ユーティリティ
**/
// レスポンスコードの取得
public function getMessagesCode (string $response): string
{
$response_array = self::json2array($response);
return $response_array['messages'][0]['code'];
}
// Bearer Session Token 取得
public function getBearerSessionToken (string $response): string
{
$response_array = self::json2array($response);
$this->bearer_session_token = $response_array['response']['token'];
return $this->bearer_session_token;
}
// JSON を 配列へ変換
public function json2array (string $json): array
{
$json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
return json_decode($json, true);
}
// cURL 実行
static function executeCurl(string $curlopt_url, string $curlopt_customrequest, array $curlopt_httpheader = [], string $current_postfields = ''): string
{
$current_postfields = !empty($current_postfields) ? json_encode(json_decode($current_postfields)) : '{}';
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $curlopt_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $curlopt_customrequest,
CURLOPT_POSTFIELDS => $current_postfields,
CURLOPT_HTTPHEADER => $curlopt_httpheader,
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
}