🌌

DirectCloud APIをPHPから叩くときに詰まったこと

2024/09/21に公開

はじめに

こんにちは、BlueZzです。

今回とある理由でDirectCloud APIをPHPから叩くことになりました。
PHPからAPIを叩くこと自体ほぼやったことが無く、
またDirectCloud APIをPHPで叩く記事を見つけられなかったのもあり、
半日ほど解決に詰まりました。

この経験をもとに、PHPからDirectCloud APIを叩く方法や気を付けることをまとめたいと思います。

バージョン情報

Windows: 11
EC-CUBE: 4.3
Docker: 27.2.0
Apache: 2.4
PHP: 8.1.2
chrome 128.0.6613.138

DirectCloudの概要

DirectCloudとは

https://directcloud.jp/
法人向けのクラウドストレージサービスです。
料金体系的にS3とかのほうが良くないかと思うのでこいつの良さはあまりわかりません。
開発者以外の方でも使いやすいとかでしょうか。

詰まったところ

https://directcloud.jp/api_reference/detail/ユーザー/Auth#アクセストークンの発行

multipart/form-dataでRequestBodyを投げているのにも関わらず、
アクセストークンが発行できませんでした。
こちらはうまくいかなかったときのコードです。

AccessTokenController.php
<?php

namespace Customize\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Routing\Annotation\Route;
use Eccube\Controller\AbstractController;

class AccessTokenController extends AbstractController
{
    /**
     * @Route("/access_token", name="access_token", methods={"POST"})
     * @Template("access_token.twig")
     */
    public function index()
    {
        $service = 'サービス名';
        $serviceKey = 'サービスキー';
        $code = '会社名';
        $id = 'ユーザーID';
        $password = 'パスワード';

        $url = 'https://api.directcloud.jp/openapi/jauth/token';

        $requestBody = [
            'service' => $service,
            'service_key' => $serviceKey,
            'code' => $code,
            'id' => $id,
            'password' => $password,
        ];

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_ENCODING, "");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Accept-Encoding: gzip, deflate, br',
            'Cache-Control: no-cache',
            'Accept: application/json',
            "Content-Type: multipart/form-data",
        ));
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);

        $response = curl_exec($ch);

        curl_close($ch);

        return [
            'res' => $response,
        ];
    }
}

サービスキーなどは管理者画面から作成します。

余談ですがEC-CUBEはSymfonyベースで作られていて、
ルーティングをroutes.ymlに書く方法とは別に
コントローラーにアノテーションとして書くことが出来ます。

コマンドでルーティング一覧を確認することもできますが、
アノテーションで書いちゃうといちいち個別にその関数を見ないとルーティングが分からんのは
不便じゃね?と思いました。

試したこと

Postmanから叩いてみる

https://www.postman.com/

APIのドキュメントを見るに必要なbody情報やリクエストの形式は間違っていないはずなので、
header情報が足りてないのかなと考えました。

どうやらUser-Agentがheaderに足りておらず、
追加してみるとふつうに叩くことが出来ました。

APIの仕様なんだとは思いますがUser-Agentが省略できないとは思いませんでした。
ちなみにUser-Agentは何でもよいです。
testとかaaaとかでも追加してさえいれば叩けるようです。

User-Agentを追加したコードは以下です。

AccessTokenController.php
<?php

namespace Customize\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Routing\Annotation\Route;
use Eccube\Controller\AbstractController;

class AccessTokenController extends AbstractController
{
    /**
     * @Route("/access_token", name="access_token", methods={"POST"})
     * @Template("access_token.twig")
     */
    public function index()
    {
        $service = 'サービス名';
        $serviceKey = 'サービスキー';
        $code = '会社名';
        $id = 'ユーザーID';
        $password = 'パスワード';

        $url = 'https://api.directcloud.jp/openapi/jauth/token';
        // ↓を追加
        $userAgent = $_SERVER['HTTP_USER_AGENT'];

        $requestBody = [
            'service' => $service,
            'service_key' => $serviceKey,
            'code' => $code,
            'id' => $id,
            'password' => $password,
        ];

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_ENCODING, "");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Accept-Encoding: gzip, deflate, br',
            'Cache-Control: no-cache',
            'Accept: application/json',
            "Content-Type: multipart/form-data",
            // ↓で設定
            "User-Agent: " . $userAgent,
        ));
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);

        $response = curl_exec($ch);

        curl_close($ch);

        return [
            'res' => $response,
        ];
    }
}

ちなみに今まで知らなかったんですが、
PostmanはAPIを叩くコードも生成してくれるんですよね。

右上のCodeをクリックすると
cURLや各種言語のコードに変換してくれます。
ただしUser-Agentなど付加してくれない情報もあるようなのでそこは注意ですね。

APIを叩くのに最低限必要な情報

DirectCloud APIを叩くときアクセスキーを使わない場合には、
service, service_key, code, id, passwordを含むRequestBody、APIエンドポイント、
User-Agentが最低限必要です。

なので、詰まったところに載せているコードには不要な部分が多くあります。
最低限必要な情報のみのせたコードがこちらです。

AccessTokenController.php
<?php

namespace Customize\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Routing\Annotation\Route;
use Eccube\Controller\AbstractController;

class AccessTokenController extends AbstractController
{
    /**
     * @Route("/access_token", name="access_token", methods={"POST"})
     * @Template("access_token.twig")
     */
    public function index()
    {
        $service = 'サービス';
        $serviceKey = 'サービスキー';
        $code = '会社名';
        $id = 'ユーザーID';
        $password = 'パスワード';

        $url = 'https://api.directcloud.jp/openapi/jauth/token';
        $userAgent = $_SERVER['HTTP_USER_AGENT'];

        $requestBody = [
            'service' => $service,
            'service_key' => $serviceKey,
            'code' => $code,
            'id' => $id,
            'password' => $password,
        ];

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            "User-Agent: " . $userAgent,
        ));
        curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);

        $response = curl_exec($ch);

        curl_close($ch);

        return [
            'res' => $response,
        ];
    }
}

削った部分の簡単な説明

詳しくはこちらをご覧ください。
https://www.php.net/manual/ja/function.curl-setopt.php

curl_setopt($ch, CURLOPT_ENCODING, "");で文字化けを防止できます。
レスポンスがgzip形式で圧縮されているらしいのでCURLOPT_ENCODINGを設定して文字化けを防ぎます。

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);はcurl_exec() の戻り値を 文字列で取得できるようにします。
文字列といいつつjson形式のレスポンスが配列になったり、
trueが1, falseの時は何も返ってこなかったりします。

CURLOPT_HTTPHEADERに設定しているものは
レスポンスの圧縮形式などなどです。
DirectCloud APIのドキュメントでは、
Content-Type: multipart/form-dataが必要なのですが、
CURLOPT_POSTFIELDSで配列を指定すると勝手に設定されるみたいなので今回は省略しても問題ないです。

Discussion