phpによるファイルアップロード

初歩的なことだと思うのですが、phpで外部サイトからファイルをアップロードするプログラムを作りたいのですが、kintoneのrest apiを見てもイメージがつかめず困っています。
どのようにリクエストヘッダを書き、どのようにレスポンスが返ってくるのでしょうか?

後藤正樹さん

ファイルの取扱については、multipart/form-data について多少理解が必要ですが、これを掴んでいくには
POSTMANやcRULコマンドで試すところから
入るのは個人的にお勧めです。file.jsonに限ったことではありませんが、POSTMANでリクエストする際にこちらにあるようにChromeのNetworkパネルでリクエストの中身を見てみるのも有効だと思います。

どのようにリクエストヘッダを書き、どのようにレスポンスが返ってくるのでしょうか?

リファレンスの通りになってしまいますが、multipartと言うだけあって、boundaryと呼ばれるもので区切りながらファイルの中身を間に入れていきます。
レスポンスとしては、fileKeyと呼ばれる値がJSONで返ってきます。

PHPであれば、

$fileName = mb_convert_encoding(mb_substr($filePath, mb_strrpos($filePath, DIRECTORY_SEPARATOR) + 1), "UTF-8", "auto");
$finfo = finfo_open(FILEINFO_MIME_TYPE);  
$mimeType = finfo_file($finfo, $filePath);  
finfo_close($finfo);  
$fileArray = array ("file" => "@$filePath;filename=$fileName;type=$mimeType");
$kintoneUrl = ($spaceId == '') ? ("https://".$subDomain.".cybozu.com/k/v1/file.json") : ("https://".$subDomain.".cybozu.com/k/guest/".$spaceId."/v1/file.json");
$authToken = base64_encode($id.":".$passWord);
$basicAuthToken = base64_encode($basicId.":".$basicPassWord);
$header = array("X-Cybozu-Authorization: $authToken", "Authorization: basic $basicAuthToken");

といった感じで、あとはリクエストヘッダ($header)、リクエストボディ($fileArray)、リクエストURL($kintoneUrl)をセットしてPOSTすれば大丈夫だと思います。

また、Excel VBAの例ですが、こちらも見比べることで参考になると思います。

いかがでしょうか?

Ryu Yamashitaさん

回答ありがとうございます。
いろいろ自分で試行錯誤しているのですが、どうもうまくいきません。
あと、もう少しだと思うのですが
status: 520 cybozu error: CB_IL02 body: {“message”:“不正なリクエストです。”,“id”:“1505999166-2079130251”,“code”:“CB_IL02”}

というエラーが起きてしまいます。

コードは以下のとおりです。

require_once("/HTTP/Request2.php");

$subDomain = "sabDomain";
$id = "loginName";
$passWord = "passWord";
$filePath = "C:/Users/m.goto/Desktop/fileupload/upload/report.php";
$appId = 121;


$fileName = mb_convert_encoding(mb_substr($filePath, mb_strrpos($filePath, DIRECTORY_SEPARATOR) + 1), "UTF-8", "auto");
//$fileName = "report.php";
$finfo = finfo_open(FILEINFO_MIME_TYPE);  
$mimeType = finfo_file($finfo, $filePath);  
finfo_close($finfo);  
$fileArray = array ("file" => "$filePath;filename=$fileName;type=$mimeType");
$kintoneUrl = "https://".$subDomain.".cybozu.com/k/v1/file.json";
$authToken = base64_encode($id.":".$passWord);
$basicAuthToken = base64_encode($id.":".$passWord);

$header = array("X-Cybozu-Authorization:". "$authToken", 
    "Host: " . $subDomain . ".cybozu.com:443",
    "Authorization: " . "basic $basicAuthToken"
);

try {

$request = new HTTP_Request2();
$request->setMethod(HTTP_Request2::METHOD_POST);

$request->setHeader($header);
$request->setUrl($kintoneUrl);
$request->setBody(json_encode($fileArray));

$request->setConfig(array(
  'ssl_verify_host' => false,
  'ssl_verify_peer' => false
));

// レスポンス取得
$response = $request->send();

// HTTP_Request2のエラーを表示
} catch (HTTP_Request2_Exception $e) {
die($e->getMessage());
// それ以外のエラーを表示
} catch (Exception $e) {
die($e->getMessage());
}

// エラー時
if ($response->getStatus() != “200”) {
echo sprintf(“status: %s”, $response->getStatus());
echo sprintf(“cybozu error: %s”, $response->getHeader(‘x-cybozu-error’));
echo sprintf(“body: %s”, $response->getBody());
die;
}

リクエストの記述方法などが間違っているのでしょうか?

自力で解決できました。
リクエストの仕方がぜんぜん違いました。
setBodyでリクエストボディを設定するのではなく、addUpLoad関数を使ったらうまくいきました。

> 自力で解決できました。

良かったです!

自力で解決できました。

反応遅れて申し訳ないですが、良かったです^^

$request->setBody(json_encode($fileArray));

少し補足ですが、こちらはfile.jsonというURLですが、ファイルについてはリクエストボディはJSON形式ではありません(Content-Type: application/jsonではない)ので、
json_encodeという訳にもいかないんですよね。

I’m trying to upload file to kintone using php. Can you help me?

az bz

Aren’t our previous snippets helpful for you?

I’m trying to upload file to kintone that will response a file key.

 

The fileKey you obtained is required to attach to kintone record like this. https://developer.kintone.io/hc/en-us/articles/212494448/ Make sense?

Yes, I want to return the file key (like this  “fileKey”: “c15b3870-7505-4ab6-9d8d-b9bdbc74f5d6”) if I upload files from an external site with php. It is possible?

setBodyでリクエストボディを設定するのではなく、addUpLoad関数を使ったらうまくいきました。

というコメントがありますが、

実際どのようなコードを書けば実現できるのでしょうか?

サンプルコードを教えて頂きたいです。

 

よろしくお願いします。

shigeyoshi tsujiuchiさん
cstapの瀧ヶ平です。

$request->setBody(json_encode($fileArray));

とある部分を

$request-\>addUpload($fileName, $filePath, $fileName, $mimeType);

のようにすれば良いのではないでしょうか?
(当方確認とっていないのでわかりませんが…)

ファイルをアップロードしてレコードに紐つけるという一連の流れをcURLを使ってゆるっと関数化したものが手元にあったので、共有します。今ならパスワード認証じゃなくてAPIトークン使う方がいいですが。

 

I found a simple snippet that allows a file to upload and attach to a record using cURL, so sharing it. It is better to replace user authentication with API token.

 

  function fileUploadToKintone($url, $fieldCode, $recordNum, $appId, $spaceId, $subDomain, $id, $passWord, $basicId, $basicPassWord){

    // prepare to upload file

    $fileName = mb_convert_encoding(mb_substr($url, mb_strrpos($url, DIRECTORY_SEPARATOR) + 1), “UTF-8”, “auto”);

    $finfo = finfo_open(FILEINFO_MIME_TYPE);

    $mimeType = finfo_file($finfo, $url);

    finfo_close($finfo);

 

    $fileArray = array (“file” => “@$url;filename=$fileName;type=$mimeType”);

    $kintoneUrl = ($spaceId == ‘’) ? (“https://”.$subDomain.“.cybozu.com/k/v1/file.json”) : (“https://”.$subDomain.“.cybozu.com/k/guest/”.$spaceId.“/v1/file.json”);

    $authToken = base64_encode($id.“:”.$passWord);

    $basicAuthToken = base64_encode($basicId.“:”.$basicPassWord);

    $header = array(“X-Cybozu-Authorization: $authToken”, “Authorization: basic $basicAuthToken”);

    // send request to upload

    $response = $this->requestHttp(‘POST’, $kintoneUrl, $header, $fileArray);

    // obtain fileKey

    $responseObject = json_decode($response);

    $fileKey = $responseObject->fileKey;

    $recordObject = new stdClass;

    // prepare to attach file to kintone record

    $fileObject = new stdClass;

    $fileObject->fileKey = $fileKey;

    $fileObjectArray = array($fileObject);

    $attachedFileObject = new stdClass;

    $attachedFileObject->value = $fileObjectArray;

 

    $recordObject->$fieldCode = $attachedFileObject;

    $requestObject = new stdClass;

    $requestObject->app = $appId;

    $requestObject->id = $recordNum;

    $requestObject->record = $recordObject;

    $requestJson = json_encode($requestObject);

    $kintoneUrl = ($spaceId == ‘’) ? (“https://”.$subDomain.“.cybozu.com/k/v1/record.json”) : (“https://”.$subDomain.“.cybozu.com/k/guest/”.$spaceId.“/v1/record.json”);

    $header = array(“X-Cybozu-Authorization: $authToken”, “Authorization: basic $basicAuthToken”, “Content-Type: application/json”);

    // send request to update record

    $response = $this->requestHttp(‘PUT’, $kintoneUrl, $header, $requestJson);

    return($response);

  }

 

 

上記のコードに従い、以下のようにソースを書いたのですが、

Status=520でエラーが「CB_IL02」

になってしまいます。

なお、「HTTP_Request2を利用したkintone REST APIの扱い方」

https://developer.cybozu.io/hc/ja/articles/202657614-HTTP-Request2%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%9Fkintone-REST-API%E3%81%AE%E6%89%B1%E3%81%84%E6%96%B9

ではうまく動作しているので、addUpLoad()の箇所がおかしいのだと思うのですが、特定できず。

ご教示ください。

 

try {

require “HTTP/Request2.php”;

$kintone_url = “https://○○○.cybozu.com/k/v1/file.json”;
$fileName = mb_convert_encoding(mb_substr($filePath, mb_strrpos($filePath, DIRECTORY_SEPARATOR) + 1), “UTF-8”, “auto”);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filePath);
finfo_close($finfo);

$req = new Http_Request2();
$req->setHeader($header);
$req->setUrl($kintone_url);
$req->setMethod(HTTP_Request2::METHOD_POST);
$req->addUpLoad(‘personal_docs’, $filePath, $fileName, $mimeType);
$response = $req->send()->getBody();

} catch (HTTP_Request2_Exception $e) {
die($e->getMessage());
// それ以外のエラーを表示
} catch (Exception $e) {
die($e->getMessage());
}

同様にcurlでも試しましたがうまくいかず・・・

コンソールからcurlで直接たたいた場合は成功しています

$header = array(
“X-Cybozu-API-Token:” . $kintone_client_api_key,
);

$fileName = mb_convert_encoding(mb_substr($filePath, mb_strrpos($filePath, DIRECTORY_SEPARATOR) + 1), “UTF-8”, “auto”);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filePath);
finfo_close($finfo);

$data = array(
‘file’ => ‘@’ . $filePath . “;filename=” . $fileName . “;type=” . $mimeType
);

$curl = curl_init(“https://○○○.cybozu.com/k/v1/file.json”);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, “POST” );
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

$res = curl_exec($curl);

すいません、自己解決しました。

postの形式が誤っていたようです。

以下、うまくいったパターンです。

$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => “https://○○○.cybozu.com/k/v1/file.json”,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => “POST”,
CURLOPT_POSTFIELDS => “------WebKitFormBoundary7MA4YWxkTrZu0gW\r”.
“Content-Disposition: form-data; name="file"; filename="$fileName"\r”.
“Content-Type: text/plain”.“\r\r”.
file_get_contents($filePath) . “\r” .
“------WebKitFormBoundary7MA4YWxkTrZu0gW–”,
CURLOPT_HTTPHEADER => array(
“X-Cybozu-API-Token: ○○○”,
“content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW”
),
));