開発情報・ナレッジ

投稿者: ShiningStar株式会社 2024年3月11日 (月)

kintoneレコード連携サンプルプログラム

この記事では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);
?> 
            
Queryの書き方についてはこちらをご確認ください。

レコード登録

<?php
// レコードの登録
$appId = XX; // アプリID
$recordData = [
    '文字列__1行_' => ['value' => 'テスト'],
    'チェックボックス' => ['value' => ['選択肢1', '選択肢2']], // チェックボックスフィールド
    'ドロップダウン' => ['value' => '選択肢A'], // ドロップダウンフィールド
    'ユーザー選択' => ['value' => [['code' => 'user1']]], // ユーザ選択フィールド
];
$response = $kintone->createRecord($appId, $recordData);
?> 
            
kintoneの仕様ではSPIRALのセレクトやマルチセレクトの値をkintone側ではドロップダウン、チェックボックスで格納する場合はラベル名で挿入する必要があるのでitem配列の当該フィールドをラベル名で置換する処理を記載しています。
ファイルをアップロードする際は後述するファイルアップロードAPIのレスポンスのファイルキーを挿入してください。
ユーザー選択の場合は下記のcodeをIDに合わせた形式にしてください。
    "ユーザー選択": {
      "value": [
        {
          "code": "sato"
        }
      ]
    } 
            
kintone側のフィールドの仕様についてはこちらをご確認ください。

レコード更新

<?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のAPIでファイルを取得した例を記載しています。
フォームのサンクス画面等、SPIRALのレコードを取得する方法は複数ありますので適宜変更してください。

こちらのサンプルを実行しただけではkintoneのレコードにファイルはアップロードされません。
kintoneのファイルアップロードの一時領域にファイルをアップロードしてファイルキーを取得する所までなので、
取得したファイルキーをレコード登録APIに含めてデータを送信する事で初めてレコードとして登録されます。
こちらで取得したファイルキーを前述したレコード登録サンプルと組み合わせてご使用ください。

解決しない場合はこちら コンテンツに関しての
要望はこちら