Uploading to Facebook

Latest update: May 2015

In this tutorial, we’ll go over uploading to Facebook. We have already released a sample Facebook script, so instead of creating a new one we’re going to go over how it works.


Facebook.html uses javascript to redirect the user to Facebook’s OAuth service. It’s just used to get the Authentication Token.


This script is used to get the "long term" access token (the one that lasts 60 days, as opposed to only 1 hour).

First, it uses fa.request and cjson to confirm that the current access token (the 1 hour version) is still valid.

local function hasValidToken(t)
    local b, c, h = fa.request {
        url = 'https://graph.facebook.com/debug_token?input_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
            t.long_term = res.data.issued_at
            if (res.data.error ~= nil) then
                t.message = res.data.error.message
                t.message = res.data.message
        return res.data.is_valid
        t.message = b
        return false

It checks the response code (c) first, and if it’s "200" (a success) will move on to deconding the JSON response. If any of these steps fail, the user does not have a valid token, and "showAuthorizationURL()" will be called - which prints a formatted string directing the user to get a new key.

If hasValidToken returns "true", we move on to requesting the long term token. Here we again use fa.request to call facebook’s OAuth API. We pass out app’s token as well as the temporary access token, and it (should) reply with the 60 day version (which is stored and later printed for the user).

local function getLongtermToken(t)
  local b, c, h = fa.request {
    url = 'https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_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)


This script manages reading the config file (facebook.cfg) for fb_get_token.lua. It returns a table (mod) containing the results.


Finally, this script uploads to Facebook. First, it waits for WiFi to be connected (waitWlanConnect()), and when it is connected goes through each folder in the upload directory and uploads them one file at a time.

LuaFileSystem is used to find and select each file (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!

Next, before uploading a folder it uses Facebook’s Graph API to create an album. This is done with a basic fa.request call, then it decodes the response string to get the album ID (which we need to make sure we upload to the right place).

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, " ", "+")
    req["method"] = 'POST'
    req["headers"] = {Connection = "close"}

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

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

Finally, each file is uploaded (uploadFile(filePath, _album_id)) using fa.request to send a POST request.

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="'
        ..'Content-Type: image/jpeg\r\n\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/'
    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
    if (c ~= 200) then
        print(h, b)
        return nil
    return c

Uploading can take quite some time!

All sample code on this page is licensed under BSD 2-Clause License