Facebookへのアップロード

最終更新: 2017/8

このチュートリアルでは、Facebookにファイルをアップロードしてみます。 本サイトでは、Facebookへアップロードする サンプルプログラムを公開していますので、ここでは、サンプルプログラムがどのように動作するかをみていきます。

Facebook.html

facebook.htmlは、FacebookのOAuthサービスへリダイレクトするためにjavascriptを使用します。これは、認証トークンを取得するために使用します。

fb_get_token.lua

fb_get_token.luaは、長期アクセストークン(60日間有効)を取得するために使用します。

まず、現在のアクセストークン(有効期限が1時間)が有効であることを確認するために、 fa.requestとcjsonを使用します。

local function hasValidToken(t)
    local b, c, h = fa.request {
        url = 'https://graph.facebook.com/debug_token?input_token='
            ..t.user_access_token..'&access_token='
            ..t.app_access_token,
        headers = {Connection = 'close'}
    }
    if (c == 200) then
        local cjson = require("cjson")
        local res = cjson.decode(b)
        cjson = nil
        if (res.error ~= nil) then
            t.message = res.error.message
        else
            t.long_term = res.data.issued_at
            if (res.data.error ~= nil) then
                t.message = res.data.error.message
            else
                t.message = res.data.message
            end
        end
        return res.data.is_valid
    else
        t.message = b
        return false
    end
end

レスポンスコード(c)を確認し、200の場合、JSONレスポンスへデコードします。いずれかのステップで失敗した場合、有効なトークンが取得できず、showAuthorizationURL()が呼ばれ、新しいキーを取得するよう指示する文字が表示されます。

hasValidTokenが「true」を返した場合、長期アクセストークンを取得しにいきます。ここで、FacebookのOAuth APIを呼び出すために、 fa.requestを再び使用します。一時的なアクセストークンを渡すと、60日間有効なアクセストークンに更新され、表示されるはずです。

local function getLongtermToken(t)
  local b, c, h = fa.request {
    url = 'https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token'
      ..'&client_id='..t.app_id
      ..'&client_secret='..t.app_secret
      ..'&fb_exchange_token='..t.user_access_token,
    headers = {Connection = 'close'}
  }

  if (c == 200) then
    local s, e = b:find("&")
    local longtermToken = b:sub(1, s - 1)
    local file = io.open( t.token_fullpath, "w" )
    file:write( longtermToken )
    io.close( file )
    file = nil

    s, e = longtermToken:find("=")
    -- Store the returned token
    t.user_access_token = longtermToken:sub(e+1, #longtermToken)
  end
end

fb_token_handler.lua

このスクリプトは、fb_get_token.lua用の設定ファイル(facebook.cfg)を管理します。結果を含むテーブル(mod)を返します。

fb_auto_up.lua

最後に、このスクリプトは、Facebookにアップロードするためのスクリプトです。まず、無線LANが接続されるのを待ちます(waitWlanConnect())。そして、接続が確立されると、アップロードディレクトリ内の各フォルダをを探索し、1回に1ファイルをアップロードします。

各ファイルを選択するために、LuaFileSystemを利用します(autoUpload())。

--...
--For each directory...
for aDirectory in lfs.dir("/DCIM") do
        local _dir_id = tonumber(aDirectory:sub(1, 3))
--        print("DIR:"..aDirectory, lfs.attributes("/DCIM/"..aDirectory, "modification"))
        if (_dir_id ~= nil and _dir_id >= lastDirectory) then
	    --for each file in that directory...
            for aFile in lfs.dir("/DCIM/"..aDirectory) do
	        --Process and upload!
--...

次に、フォルダをアップロードする前に、アルバムを作成するためにFacebookのGraph APIを使います。これは、基本的な fa.requestでリクエストを発行します。正しい場所にアップロードするために、レスポンス文字列をデコードし、アルバムIDを取得します。

local function createAlbum(_name, _message)
    local req = {}
    req["url"] = 'https://graph.facebook.com/v2.1/me/albums?access_token='..user_access_token
        ..'&name='..string.gsub (_name, " ", "+")
        ..'&message='..string.gsub (_message, " ", "+")
        ..'&privacy=%7B%22value%22%3A+%22SELF%22%7D'
    req["method"] = 'POST'
    req["headers"] = {Connection = "close"}

    local b,c,h = fa.request(req)
    if (c ~= 200) then
        print(h, b)
        return nil
    end
    req = nil

    c, h = nil
    local cjson = require("cjson")
    local res = cjson.decode(b)
    collectgarbage()
    return res["id"]
end

最後に、POSTリクエストを発行するために、 fa.requestを使用して各ファイルのアップロードを行います。(uploadFile(filePath, _album_id))

local function uploadFile(filePath, _album_id)
    local boundary = '--bnfDxpKY69NKk'
    local headers = {}
    local place_holder = '<!--WLANSDFILE-->'

    headers['Connection'] = 'close'
    headers['Content-Type'] = 'multipart/form-data; boundary="'..boundary..'"'

    local body = '--'..boundary..'\r\n'
        ..'Content-Disposition: form-data; name="source"; filename="'
        ..filePath..'"\r\n'
        ..'Content-Type: image/jpeg\r\n\r\n'
        ..'<!--WLANSDFILE-->\r\n'
        .. '--' .. boundary .. '--\r\n'

    headers['Content-Length'] =
        lfs.attributes(filePath, 'size')
        + string.len(body)
        - string.len(place_holder)

    local args = {}
    args["url"] = 'https://graph.facebook.com/v2.1/'
            .._album_id..'/photos?access_token='
            ..user_access_token
            ..'&message='..filePath
    args["method"] = "POST"
    args["headers"] = headers
    args["body"] = body
    args["file"] = filePath
    args["bufsize"] = 1460*10
    local b,c,h = fa.request(args)
    b, h = nil
    collectgarbage()
    if (c ~= 200) then
        print(h, b)
        return nil
    end
    return c
end

アップロードには数分かかる場合があります。

サンプルコード

リポジトリを見る(GitHub)

このサイトのサンプルコードは 二条項BSDライセンスで提供されています。