【PHP】Facebook広告APIをcurlで操作したい！

#はじめに

今まで広告関係では、

・Google広告のAPI
・Yahoo検索広告
・Yahooディスプレイ広告

について、
**ライブラリを使わず直で叩く！**をモットーに
あれこれ調べ試行錯誤して導入してきました。
YahooはAPIを統一してくれ。。。

APIで使ってきた機能は
広告費やクリック数、インプレッション数などの
レポート情報を取得することと、
入札単価を更新すること。

さて、そんな中、
今回新たにFacebook広告もAPI化したいということで、
運用の方から調査依頼がきましたよ！わくわく！！

調べてみたところ、FacebookのAPIは通称**グラフAPI**というらしい。
2021/12現在の最新バージョンはv12.0。
ドキュメントは[こちら](https://developers.facebook.com/docs/graph-api?locale=ja_JP)

一方、Facebook広告で使いたい機能を検索して
出てくるのは**マーケティングAPI**。
ドキュメントは[こちら](https://developers.facebook.com/docs/marketing-apis)

資料もたくさん揃えてくれててなんて親切なんでしょう。
（ほとんど日本語版はないけど）

マーケティングAPIもグラフAPIも、
「API」って付くからそれぞれ独立したAPIなのかと思っていたわけですが、
どうやらマーケティングAPIはグラフAPIの拡張版みたいなやつ？らしく。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566860/2c7bd47b-b0f9-c341-e4ec-80ea4db02265.png)

それってつまり**ただのグラフAPI**。。。

機能的に必要なのはマーケティングAPIなのですが、
エンドポイントはgraphなのです。
ライブラリの１つってかんじかな。

まぎらわしい。。

なので、考えるべきは
**「グラフAPIをどう導入するか」**
ということになります。


#APIを使うための準備

どの媒体を利用するにしても、
APIを使えるようにするためにまずはあれこれ準備作業が必要です。
私は毎回この作業で躓いて心バッキバキに折られてきたわけで。

Googleほんとめんどくさかったな。
ドキュメント英語だし
資料ありすぎて何見ていいかわからんし。

Yahooは、取り掛かったのがGoogleのあとだったってのと
ドキュメント日本語だし、機能も絞り込まれてて
（絞り込まれてるゆえに、逆にめんどくさいことも多い）
比較的親切でわかりやすかったな。

Facebookはどうか。

結論：
**じみにわかりにくい。**

でも導入に関してはググると、結構情報が出てきたので助かりました。

参考にしたサイトは
以下の手順説明の際に紹介させていただきます。

##手順１：Facebookビジネスアカウントを作る

私はすでにアカウントがある状態から始めているので
作り方については詳しくないです。
がんばって作ってください・・・

参考は[こちら](https://www.comnico.jp/we-love-social/facebook-business-manager)など。。

##手順２：Facebook for developersにビジネスIDを登録する

[for developers](https://developers.facebook.com/?locale=ja_JP)にビジネスIDでログインします。
（ログイン？紐付け？どっちか忘れたけど）

APIを使うためには、「アプリ」というものを登録する必要があります。

ということで右上の「アプリ作成」から

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566860/1303621e-e90e-f30e-2cbe-d74a42053770.png)

アプリタイプをえらび、次へ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566860/c0cbd8b7-e28b-812f-cec9-81d8c2cfeec9.png)

名前やメアドなど必要な項目を入力し、アプリを作成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566860/05110c26-8442-1cc1-e142-623bcd017c8c.png)
たぶんパスワード入力求められる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566860/17004e3b-1d72-6389-99b3-54c62d6b6d1a.png)

「アプリを製品に追加」の画面が表示されるので、
ここで「マーケティングAPI」を選びましょう。

あとはドキュメント見ろとかSDK入れるとか紹介されるけど、
基本あとでも確認できるので無視で大丈夫です。

##手順３：アクセストークンを取得する

APIを利用するためには、鍵である**アクセストークン**が必要です。

FacebookAPIのアクセストークンは、GoogleやYahooのAPIとは違い、
手順２で設定したアプリの画面から生成できます。

ただし２時間の期限付き。
[アクセストークンデバッガー](https://developers.facebook.com/tools/debug/accesstoken/)というツールを使って
最大２ヶ月（３ヶ月？）までは延長できます。

システムに組み込む場合は、
期限ごとにアクセストークンを変更する必要があります。

うーん・・・めんどくさ(ry

なんとかならんもんかと調べたところ、
期限なしアクセストークンというのが作れるとのこと。

セキュリティ的には定期的に入れ替えるのがベストだとは思うけど、
とりあえず期限は気にせず使えるやつがほしい！！！

という手順を書いていただいたありがたい説明が[こちら](https://qiita.com/ari-chel/items/1bb8c0135dd7ec33d261)
あと[こちら](https://analyzegear.co.jp/blog/1392)も参考になりましたありがとうございました。

注意として、
「アクセス許可」に**pages_show_list**を付けるのを忘れないようにしましょう。
これしないと、アクセストークンデバッガーで「me/accounts」しても無反応です。
私できなくてこれで１日悩みました。。

設定したアクセストークンは、パスワード級に保管。

つぎに、アプリ左メニューの「設定」->「ベーシック」を開くと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566860/2c9b4ecd-9959-f569-a6df-c8583b8c8996.png)

**app secret**がパスワード表示されています。
「表示」をクリックしてパスワード入力すると正しいものが表示されます。

これも実質パスワード扱いなので、厳重保管で。

ここまできたら、準備完了です。
あとは鍵を渡してデータ取得！

##広告アカウントに紐づくキャンペーンを取ってみる

GoogleでもYahooでも、PHP＋curlでデータ取ってるので
（意地でもライブラリは使わない）
今回もcurlでやります。直取りで！！

API認証には、アクセストークンとともに、
アクセストークンとapp secretを暗号化した**appsecret_proof**という鍵を使います。
ドキュメントは[こちら](https://developers.facebook.com/docs/graph-api/securing-requests%20?locale=ja_JP)

FacebookAPIは非常に簡単で、エンドポイントにGETでパラメータを渡します。
googleやyahooみたくheaderが不要です。
ドキュメントにちゃんとcURLでの取り方も書いてくれてて親切。

ノード（階層）によってパラメータが多少変わるので注意。

```
//エンドポイント
$endpoint = "https://graph.facebook.com";

//バージョン：2021/12最新
$version = "v12.0";

//広告アカウントID
$_ad_account_id = "AD_ACCOUNT_ID";

//アクセストークン
$access_token = "ACCESS_TOKEN";

//app secret
$app_secret = "APP_SECRET";

//appsecret_proofを生成
$appsecret_proof= hash_hmac('sha256', $access_token, $app_secret); 

//広告アカウントに紐付いたキャンペーン一覧を取る
//デフォルトで上限25件なので、複数取りたい場合はlimit=1000とかを追加する
$_url = "$endpoint/$version/act_$_ad_account_id/campaigns?";
$_url .= "access_token=$access_token&appsecret_proof=$appsecret_proof";
$_url .= "&fields=id,name,account_id,bid_strategy,status";

//curl START
$_curl = curl_init();

//OPTIONをセット
curl_setopt_array($_curl, [
	CURLOPT_URL => $_url,
	CURLOPT_RETURNTRANSFER => true,
	CURLOPT_TIMEOUT => 120,
]);

//curl EXEC(文字列で取得)
$_resp = curl_exec($_curl);

//エラーハンドリング用
$_errno = curl_errno($_curl);

//curl END
curl_close($_curl);

//エラーハンドリング
if ($_errno !== CURLE_OK) {
}
```

GETパラメータにつけてるfields項目で
SELECTする項目を指定します。


#ノードの構造について

詳細は[リファレンス](https://developers.facebook.com/docs/marketing-api/reference/v12.0)参照。

URL指定の際に、{ノード}/{エッジ}という指定をします。

ノードに、広告グループIDやキャンペーンなどで
エッジが操作にあたります。

マーケティングAPIの構造としては

>広告アカウント　＞　キャンペーン　＞　広告セット（広告グループ）　＞　広告

となっていて、
各情報の詳細はひとつ下の階層まで取れるようです。

たとえばキャンペーンを指定して取るとき、

```
//キャンペーンID
$_campaign_id = "CAMPAIGN_ID";

//A:広告アカウントのノード
$_url = "$endpoint/$version/act_$_ad_account_id/campaigns?";
$_url .= "access_token=$access_token&appsecret_proof=$appsecret_proof";
$_url .= "&campaign_id=$_campaign_id";

//B:キャンペーンのノード
$_url = "$endpoint/$version/$campaign_id/?";
$_url .= "access_token=$access_token&appsecret_proof=$appsecret_proof";
```

fieldsで指定できる項目は多少異なるかもしれませんが、
AとBで取れるものは基本的に同じです。

Aに広告セットIDを指定しても（&adset_id=XXXXというかんじ）
絞り込んでくれませんでした。エラーにはならなかったけど。

同様に、広告セットを指定して取るときは、

```
//広告セットID
$_adset_id = "ADSET_ID";

//A:キャンペーンのノード
$_url = "$endpoint/$version/$campaign_id/adsets?";
$_url .= "access_token=$access_token&appsecret_proof=$appsecret_proof";
$_url .= "&adset_id=$_adset_id ";

//B:広告セットのノード
$_url = "$endpoint/$version/$_adset_id /?";
$_url .= "access_token=$access_token&appsecret_proof=$appsecret_proof";
```

となります。
AでもBでも情報が取れるはず。

#広告レポートを取ってみる

キャンペーンや広告セット情報が取れたので、
次に肝心のレポートを取ってみます。

Facebook広告のレポートは「インサイト」と呼ばれるものらしいので
[ドキュメント](https://developers.facebook.com/docs/marketing-api/reporting)でもinsightsってのを探しましょう。

呼び出し方としては、前述と変わらず、
認証情報とほしい項目と条件を全部GETで渡すだけです。

たとえば、
2021/11/24～25の広告セットのレポートを取る場合。

```
$_url = "$endpoint/$version/$campid/insights?";
$_url .= "access_token=$access_token&appsecret_proof=$appsecret_proof";
$_url .= "&level=adset";//levelに取りたいノードを指定
$_url .= "&fields=campaign_id,campaign_name,adset_id,adset_name,impressions,clicks,spend";
$_url .= "&time_range={'since':'2021-11-24','until':'2021-11-25'}";
$_url .= "&limit=10000";//デフォルト25件＋ページング情報で返って来るので、たくさんある場合はlimit指定必須
~~~

上記の指定にすると、数値はすべて24～25の合計値が戻ってきます。

たとえばこれを１日ごとに欲しい場合は、条件をさらに追加して

```
$_url .= "&time_increment=1";
```

さらにこれを１時間単位で取りたい場合は、条件に

```
$_url .= "&breakdowns=['hourly_stats_aggregated_by_advertiser_time_zone']";
```
のように指定します。

ドキュメントは基本英語なので分かりにくい部分もありつつ、
いろんな条件を用意してくれているので
細かい情報も取ってこれるようになっています。

#予算を更新してみる

これまではAPIから情報を参照していただけですが、
登録処理はどうやるのか。

今回は「１日の予算」という項目をアップデートしてみます。

ドキュメントは[こちら](https://developers.facebook.com/docs/marketing-api/bidding/overview/budgets)

データ取得はずっとGETリクエストだったわけですが、
更新処理はPOSTリクエストになるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566860/deab4164-e8fa-6fcd-ad3e-79c72c969cde.png)

なんでできないの～！？と１日悩んでしまったわけですが
なんてことないPOSTを見逃してただけです。
ちゃんと読めと。。

```
//UPDATEはPOSTリクエスト
$_url = "$endpoint/$_version/$_adset_id";

$_param = [
	"access_token" => $access_token,
	"appsecret_proof" => $appsecret_proof,
	"daily_budget" => "3000",
];

//curl START
$_curl = curl_init();

//OPTIONをセット
curl_setopt_array($_curl, [
    CURLOPT_URL => $_url,
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 120,
    CURLOPT_POSTFIELDS => $_param,
]);

//curl EXEC(文字列で取得)
$_resp = curl_exec($_curl);

//エラーハンドリング用
$_errno = curl_errno($_curl);

//curl END
curl_close($_curl);

//エラーハンドリング
if ($_errno !== CURLE_OK) {
    //エラーハンドリング
}
```

新規登録も基本的に同じではないかと思います。
（試してないけど）

#おわりに

Facebook広告APIで検索してみても、
広告の設定方法とか説明はたくさん出てきても
ほしい技術的な情報があんまり出てこなかったので、
自分なりに試行錯誤した結果をメモしてみました。

バージョン変わったりすると仕様も変わるし、
APIによって作りもさまざまなので
都度アップデートしていかないといけないなあと思っています。

おわり。