この記事では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に含めてデータを送信する事で初めてレコードとして登録されます。
こちらで取得したファイルキーを前述したレコード登録サンプルと組み合わせてご使用ください。