Facebook PHP SDK で写真を投稿する

Facebook のデータを利用するときは基本的に Graph API Reference を参考にすればよいが、写真を投稿するときにつまづいたのでメモ。

結論としては次のようなコードになる。

<?php

$postTo = 'suzumekawaii'; // ユーザ名もしくはページ名
$message = 'すずめかわいい'; // 投稿する文章
$imagePath = '/path/to/photo.jpg'; // 投稿する画像ファイルのパス

$facebook = new Facebook($fbParams);
$facebook->setAccessToken($accessToken);

$facebook->setFileUploadSupport(true); // *1

$params = array(
    'message' => $message,
    'source' => '@' . $imagePath, // *2
);

try {
    $result = $facebook->api("/$postTo/photo", 'POST', $params);
}
catch (FacebookApiException $e) {
    die('failed to post: ' . $e->getMessage());
}

ポイントは *1 で setFileUploadSupport(true) を設定することである。これがないと画像ファイルが送信されず、エラー #324 “Requires upload file” が帰ってくる。

また *2 の箇所でファイル名の前に @ を付けるのは PHP SDK が内部で CURL を使っていることによるもの。curl_setopt のマニュアルの CURLOPT_POSTFIELDS の項に詳しく書かれている。ただこの書き方は PHP 5.5.0 以降で非推奨となっている。

ちなみに内部の処理は次のように書かれている (base_facebook.php)。

<?php

...

  /**
   * Indicates if the CURL based @ syntax for file uploads is enabled.
   *
   * @var boolean
   */
  protected $fileUploadSupport = false;

...

  protected function makeRequest($url, $params, $ch=null) {
    if (!$ch) {
      $ch = curl_init();
    }

    $opts = self::$CURL_OPTS;
    if ($this->getFileUploadSupport()) {
      $opts[CURLOPT_POSTFIELDS] = $params;
    } else {
      $opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&');
    }

...

なるほど $fileUploadSupport が false のままでは POST データを http_build_query で作ってしまい、うまくいかないわけだ。