この記事ではSPIRALから株式会社サイボウズのkintoneへのレコード連携について、メソッドごとにサンプルコードをまとめています。
SPIRAL ver.1 とkintoneをAPI連携したアプリケーションを構築する時の参考になれば幸いです。
共通モジュール
<?php //------------------------------ // 共通モジュール //------------------------------ class KintoneAPI { private $subdomain; private $apiToken; private $user; private $password; public function __construct($subdomain, $apiToken = '', $user = '', $password = '') { $this->subdomain = $subdomain; $this->apiToken = $apiToken; $this->user = $user; $this->password = $password; } private function callAPI($method, $apiPath, $data = []) { $url = "https://{$this->subdomain}.cybozu.com/k/v1{$apiPath}"; $headers = [ 'Content-Type: application/json', ]; // APIトークンが設定されている場合は、認証ヘッダーを追加 if (!empty($this->apiToken)) { $headers[] = 'X-Cybozu-API-Token: ' . $this->apiToken; } $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { throw new Exception("cURL Error: " . $err); } else { return json_decode($response, true); } } public function createRecord($appId, $recordData) { return $this->callAPI('POST', "/record.json", ['app' => $appId, 'record' => $recordData]); } public function updateRecord($appId, $recordId, $recordData) { return $this->callAPI('PUT', "/record.json", ['app' => $appId, 'id' => $recordId, 'record' => $recordData]); } public function deleteRecord($appId, $recordIds) { return $this->callAPI('DELETE', "/records.json", ['app' => $appId, 'ids' => $recordIds]); } public function getRecords($appId, $query = '', $fields = []) { $apiPath = "/records.json"; $data = [ 'app' => $appId, 'query' => $query, 'fields' => $fields, ]; return $this->callAPI('GET', $apiPath, $data); } public function uploadFile($fileData, $fileName) { $url = "https://{$this->subdomain}.cybozu.com/k/v1/file.json"; $boundary = uniqid(); $mimeType = $this->getMimeType($fileName); // マルチパートのボディを構築 $body = "--$boundary\r\n"; $body .= "Content-Disposition: form-data; name=\"file\"; filename=\"$fileName\"\r\n"; $body .= "Content-Type: $mimeType\r\n\r\n"; $body .= $fileData . "\r\n"; $body .= "--$boundary--\r\n"; $headers = [ "X-Cybozu-API-Token: {$this->apiToken}", "Content-Type: multipart/form-data; boundary=$boundary", ]; $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $body); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); $response = curl_exec($curl); curl_close($curl); if (!$response) { throw new Exception("Failed to upload file to kintone."); } $responseArray = json_decode($response, true); if (!isset($responseArray["fileKey"])) { throw new Exception("No file key returned from kintone."); } return $responseArray["fileKey"]; } private function getMimeType($fileName) { // strrposでファイル名の中で最後に出現するドットの位置を見つける $lastDotPosition = strrpos($fileName, '.'); if ($lastDotPosition === false) { // ファイル名にドットがない場合は拡張子がないとみなし、'application/octet-stream'を返す return 'application/octet-stream'; } // substrでドットの位置以降の文字列(拡張子)を取得し、strtolowerで小文字にする $extension = strtolower(substr($fileName, $lastDotPosition + 1)); // 拡張子に基づいてMIMEタイプを判断 switch ($extension) { case 'jpg': case 'jpeg': return 'image/jpeg'; case 'png': return 'image/png'; case 'gif': return 'image/gif'; case 'pdf': return 'application/pdf'; default: return 'application/octet-stream'; // 不明なファイル形式の場合 } } } ?>
設定値
<?php //------------------------------ // 設定値 //------------------------------ // kintone設定値以下は使用例です。実際のアプリID、レコードデータ、APIトークンまたはユーザー名/パスワードを適宜設定してください。 $subdomain = ''; // サブドメインを設定 $apiToken = ''; // APIトークンを設定(APIトークン認証を使用する場合 ※基本的にはAPIトークン認証を用いてください。) $user = 'yourUsername'; // ユーザー名(基本認証を使用する場合) $password = 'yourPassword'; // パスワード(基本認証を使用する場合) // キントーンAPIクラスのインスタンスを作成 $kintone = new KintoneAPI($subdomain, $apiToken, $user, $password); ?>
使用例
<?php //------------------------------ // 設定値 //------------------------------ // kintone設定値以下は使用例です。実際のアプリID、レコードデータ、APIトークンまたはユーザー名/パスワードを適宜設定してください。 $subdomain = ''; // サブドメインを設定 $apiToken = ''; // APIトークンを設定(APIトークン認証を使用する場合) $user = 'yourUsername'; // ユーザー名(基本認証を使用する場合) $password = 'yourPassword'; // パスワード(基本認証を使用する場合) // キントーンAPIクラスのインスタンスを作成 $kintone = new KintoneAPI($subdomain, $apiToken, $user, $password); //------------------------------ // API実行 //------------------------------ // レコードの登録 //SPIRALのレコードをAPIで取得して登録する場合 //SPIRALレコード取得(アカウント内API ONにしてください) $id = $SPIRAL->getContextByFieldTitle("id"); $db = $SPIRAL->getDataBase("kintone"); $db->addEqualCondition("id", $id); $db->addSelectFields("text", "select", "multiSelect"); $db->setLinesPerPage(500); $result = $db->doSelect(); // レコードデータの初期化 $recordData = [ '文字列__1行_' => ['value' => ''], 'チェックボックス' => ['value' => []], 'ドロップダウン' => ['value' => ''], ]; // 結果データの処理 if (!empty($result['data'][0])) { $item = $result['data'][0]; // テキストフィールド $recordData['文字列__1行_']['value'] = $item['text'] ?? ''; // チェックボックスフィールド $multiSelectValues = explode(',', $item['multiSelect'] ?? ''); $recordData['チェックボックス']['value'] = array_map(function($value) use ($result) { return $result['label'][2][$value] ?? $value; }, $multiSelectValues); // ドロップダウンフィールド $recordData['ドロップダウン']['value'] = $result['label'][1][$item['select']] ?? ''; } $response = $kintone->createRecord($appId, $recordData); //------------------------------ // 共通モジュール //------------------------------ class KintoneAPI { private $subdomain; private $apiToken; private $user; private $password; public function __construct($subdomain, $apiToken = '', $user = '', $password = '') { $this->subdomain = $subdomain; $this->apiToken = $apiToken; $this->user = $user; $this->password = $password; } private function callAPI($method, $apiPath, $data = []) { $url = "https://{$this->subdomain}.cybozu.com/k/v1{$apiPath}"; $headers = [ 'Content-Type: application/json', ]; // APIトークンが設定されている場合は、認証ヘッダーを追加 if (!empty($this->apiToken)) { $headers[] = 'X-Cybozu-API-Token: ' . $this->apiToken; } $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { throw new Exception("cURL Error: " . $err); } else { return json_decode($response, true); } } public function createRecord($appId, $recordData) { return $this->callAPI('POST', "/record.json", ['app' => $appId, 'record' => $recordData]); } public function updateRecord($appId, $recordId, $recordData) { return $this->callAPI('PUT', "/record.json", ['app' => $appId, 'id' => $recordId, 'record' => $recordData]); } public function deleteRecord($appId, $recordIds) { return $this->callAPI('DELETE', "/records.json", ['app' => $appId, 'ids' => $recordIds]); } public function getRecords($appId, $query = '', $fields = []) { $apiPath = "/records.json"; $data = [ 'app' => $appId, 'query' => $query, 'fields' => $fields, ]; return $this->callAPI('GET', $apiPath, $data); } public function uploadFile($fileData, $fileName) { $url = "https://{$this->subdomain}.cybozu.com/k/v1/file.json"; $boundary = uniqid(); $mimeType = $this->getMimeType($fileName); // マルチパートのボディを構築 $body = "--$boundary\r\n"; $body .= "Content-Disposition: form-data; name=\"file\"; filename=\"$fileName\"\r\n"; $body .= "Content-Type: $mimeType\r\n\r\n"; $body .= $fileData . "\r\n"; $body .= "--$boundary--\r\n"; $headers = [ "X-Cybozu-API-Token: {$this->apiToken}", "Content-Type: multipart/form-data; boundary=$boundary", ]; $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $body); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); $response = curl_exec($curl); curl_close($curl); if (!$response) { throw new Exception("Failed to upload file to kintone."); } $responseArray = json_decode($response, true); if (!isset($responseArray["fileKey"])) { throw new Exception("No file key returned from kintone."); } return $responseArray["fileKey"]; } private function getMimeType($fileName) { // strrposでファイル名の中で最後に出現するドットの位置を見つける $lastDotPosition = strrpos($fileName, '.'); if ($lastDotPosition === false) { // ファイル名にドットがない場合は拡張子がないとみなし、'application/octet-stream'を返す return 'application/octet-stream'; } // substrでドットの位置以降の文字列(拡張子)を取得し、strtolowerで小文字にする $extension = strtolower(substr($fileName, $lastDotPosition + 1)); // 拡張子に基づいてMIMEタイプを判断 switch ($extension) { case 'jpg': case 'jpeg': return 'image/jpeg'; case 'png': return 'image/png'; case 'gif': return 'image/gif'; case 'pdf': return 'application/pdf'; default: return 'application/octet-stream'; // 不明なファイル形式の場合 } } } ?>
レコード取得
<?php // レコードの取得 $appId = XX; // アプリID $query = 'レコード番号 >= 100 order by レコード番号 desc limit 100'; // 取得条件 $fields = ['文字列__1行_', '日付']; // 取得するフィールド $response = $kintone->getRecords($appId, $query, $fields); ?>
レコード登録
<?php // レコードの登録 $appId = XX; // アプリID $recordData = [ '文字列__1行_' => ['value' => 'テスト'], 'チェックボックス' => ['value' => ['選択肢1', '選択肢2']], // チェックボックスフィールド 'ドロップダウン' => ['value' => '選択肢A'], // ドロップダウンフィールド 'ユーザー選択' => ['value' => [['code' => 'user1']]], // ユーザ選択フィールド ]; $response = $kintone->createRecord($appId, $recordData); ?>
ファイルをアップロードする際は後述するファイルアップロードAPIのレスポンスのファイルキーを挿入してください。
ユーザー選択の場合は下記のcodeをIDに合わせた形式にしてください。
"ユーザー選択": { "value": [ { "code": "sato" } ] }
レコード更新
<?php // レコードの更新 $appId = XX; // アプリID $recordId = 456; // 更新するレコードのID $updateData = [ 'fieldCode' => ['value' => 'Updated Value'] ]; $response = $kintone->updateRecord($appId, $recordId, $updateData); ?>
レコード削除
<?php // レコードの削除 $appId = XX; // アプリID $recordIds = [456, 789]; // 削除するレコードのIDの配列 $response = $kintone->deleteRecord($appId, $recordIds); ?>
ファイルアップロード
<? // ファイルアップロード //SPIRALレコード取得 // SPIRAL APIの設定 $locator = "https://www.pi-pe.co.jp/api/locator"; // ロケータのURL $TOKEN = ""; // あなたのAPIトークン $SECRET = ""; // あなたのシークレット // API用のHTTPヘッダ $api_headers = array( "X-SPIRAL-API: locator/apiserver/request", "Content-Type: application/json; charset=UTF-8", ); // 送信するJSONデータを作成 $parameters = array(); $parameters["spiral_api_token"] = $TOKEN; //トークン // 送信用のJSONデータを作成します。 $json = json_encode($parameters); // curlライブラリを使って送信します。 $curl = curl_init($locator); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $json); curl_setopt($curl, CURLOPT_HTTPHEADER, $api_headers); curl_exec($curl); // エラーがあればエラー内容を表示 if (curl_errno($curl)) echo curl_error($curl); $response = curl_multi_getcontent($curl); curl_close($curl); $response_json = json_decode($response, true); // サービス用のURL $APIURL = $response_json['location']; $id = $SPIRAL->getContextByFieldTitle("id"); // リクエストボディに含めるデータ $parameters = [ "spiral_api_token" => $TOKEN, "passkey" => time(), // 現在のエポック秒 "db_title" => "kintone", // データベースタイトル "file_field_title" => "file", // ファイルフィールドタイトル "key_field_title" => "id", // キーフィールドタイトル "key_field_value" => $id, // キーフィールド値 ]; // 署名の生成 $key = $parameters["spiral_api_token"] . "&" . $parameters["passkey"]; $parameters["signature"] = hash_hmac('sha1', $key, $SECRET, false); // JSONエンコード $json = json_encode($parameters); // API用HTTPヘッダー $api_headers = [ "X-SPIRAL-API: database/get_file/request", "Content-Type: application/json; charset=UTF-8", ]; // cURLセッションの初期化 $curl = curl_init($APIURL); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $json); curl_setopt($curl, CURLOPT_HTTPHEADER, $api_headers); // リクエストの実行 $response = curl_exec($curl); // エラーチェック if (curl_errno($curl)) { echo "cURL Error: " . curl_error($curl); } else { // 応答をデコードして表示 $response_data = json_decode($response, true); print_r($response_data); } // cURLセッションの終了 curl_close($curl); //kintoneAPI送信 $fileData = $response["data"]; $fileName = $response["file_name"]; $response = $kintone->uploadFile($fileData,$fileName); ?>
フォームのサンクス画面等、SPIRALのレコードを取得する方法は複数ありますので適宜変更してください。
こちらのサンプルを実行しただけではkintoneのレコードにファイルはアップロードされません。
kintoneのファイルアップロードの一時領域にファイルをアップロードしてファイルキーを取得する所までなので、
取得したファイルキーをレコード登録APIに含めてデータを送信する事で初めてレコードとして登録されます。
こちらで取得したファイルキーを前述したレコード登録サンプルと組み合わせてご使用ください。