it-swarm-ru.tech

Facebook Graph API - загрузка фотографий с использованием JavaScript

Можно ли загрузить файл с помощью API Graph Facebook с использованием JavaScript, я чувствую, что я близок. Я использую следующий JavaScript

var params = {};
params['message'] = 'PicRolled';
params['source'] = '@'+path;
params['access_token'] = access_token;
params['upload file'] = true;

function saveImage() {
    FB.api('/me/photos', 'post', params, function(response) {
        if (!response || response.error) {
            alert(response);
        } else {
            alert('Published to stream - you might want to delete it now!');
        }
    }); 
}

При запуске этого я получаю следующую ошибку ...

"OAuthException" - "(#324) Requires upload file"

Когда я пытаюсь исследовать этот метод, все, о чем я могу узнать, это метод php, который должен решить эту проблему.

$facebook->setFileUploadSupport(true);

Тем не менее, я использую JavaScript, похоже, этот метод может быть связан с разрешениями Facebook Graph, но я уже установил разрешения user_photos и publish_stream, которые, по моему мнению, являются единственными, которые мне нужны для выполнения этой операции.

Я видел пару оставшихся без ответа вопросов по этому поводу в stackoverflow, надеюсь, я смогу объяснить себя достаточно. Спасибо, парни.

40
Moz

Правка: этот ответ (в настоящее время) в значительной степени не имеет значения. Если ваше изображение находится в Интернете, просто укажите параметр url согласно API (см. Примеры в других ответах). Если вы хотите POST размещать изображения непосредственно на Facebook, вы можете прочитать этот ответ, чтобы получить понимание. Также см. HTML5 Canvas.toDataUrl().

API говорит : «Чтобы опубликовать фотографию, выполните запрос POST с вложением файла фотографии в виде multipart/form-data

FB ожидает, что байты загружаемого изображения находятся в теле HTTP-запроса, но их там нет. Или посмотреть на это по-другому - где в вызове FB.api () вы предоставляете фактическое содержимое самого изображения? 

API FB.api () плохо документирован и не предоставляет пример HTTP POST, который включает тело. Из отсутствия такого примера можно сделать вывод, что он этого не поддерживает.

Это, вероятно, нормально - FB.api () использует что-то, называемое XmlHttpRequest, под обложками, которые делает, включая тело ... посмотрите это в своей любимой ссылке на JavaScript.

Тем не менее, вам все равно придется решить 2 подзадачи:

  1. как подготовить байты изображения (и остальную часть запроса) как multipart/form-data ; а также
  2. получать байты самого изображения

(кстати, необходимость кодировать тело сообщения, вероятно, является тем, для чего предназначен метод PHP setFileUploadSupport (true) - скажите объекту facebook, что перед отправкой кодируйте тело сообщения как multipart/form-data)

Но это немного мееше, чем это

К сожалению, подзадача «2» может вас укусить - нет способа (в прошлый раз, когда я смотрел) извлечь байты изображения из предоставленного браузером объекта Image. 

Если загружаемое изображение доступно через URL, вы можете получить байты с помощью XmlHttpRequest. Не так уж плохо.

Если изображение поступает с рабочего стола пользователя, вы можете предложить пользователю:

 <form enctype="multipart/form-data">
     <input type="filename" name="myfile.jpg" />
     <input type="hidden" name="source" value="@myfile.jpg"/>
     <input type="hidden" name="message" value="My Message"/>
     <input type="hidden" name="access_token" value="..."/> 
 </form> 

(обратите внимание, что source ссылается на имя, данное виджету загрузки файлов)

... и надеюсь, что FB ожидает получения данных таким образом (сначала попробуйте использовать статическую HTML-форму, а затем динамически кодировать ее в JS). Можно сделать вывод, что на самом деле это так, поскольку они не предлагают другого способа сделать это.

26
David Bullock

Да, это возможно, я нахожу 2 решения, как это сделать, и они очень похожи друг другу, вам нужно просто определить параметр URL для URL внешнего изображения

Первый с использованием Javascript SDk:

var imgURL="http://farm4.staticflickr.com/3332/3451193407_b7f047f4b4_o.jpg";//change with your external photo url
FB.api('/album_id/photos', 'post', {
    message:'photo description',
    url:imgURL        
}, function(response){

    if (!response || response.error) {
        alert('Error occured');
    } else {
        alert('Post ID: ' + response.id);
    }

});

и ВТОРОЙ, используя jQuery Post request и FormData:

 var postMSG="Your message";
 var url='https://graph.facebook.com/albumID/photos?access_token='+accessToken+"&message="+postMSG;
 var imgURL="http://farm4.staticflickr.com/3332/3451193407_b7f047f4b4_o.jpg";//change with your external photo url
 var formData = new FormData();
 formData.append("url",imgURL);

  $.ajax({
                    url: url,
                    data: formData,
                    cache: false,
                    contentType: false,
                    processData: false,
                    type: 'POST',

                    success: function(data){
                        alert("POST SUCCESSFUL");
                    }
                });
44
Владимир Дворник

я использовал код @ Владимир Дворник с некоторыми изменениями, у меня была та же проблема, и с этим кодом это работало очень хорошо:

        var imgURL = //your external photo url
        FB.api('/photos', 'post', {
            message: 'photo description',
            access_token: your accesstoken 
            url: imgURL
        }, function (response) {

            if (!response || response.error) {
                alert('Error occured:' + response);
            } else {
                alert('Post ID: ' + response.id);
            }

        });
17
Arrabi

Фотографии могут быть загружены в профиль Facebook с помощью Ajax следующим образом.

$.ajax({
            type: "POST",
            url: "https://graph.facebook.com/me/photos",
            data: {
                message: "Your Msg Goes Here",
                url: "http://www.knoje.com/images/photo.jpg[Replace with yours]",
                access_token: token,
                format: "json"
            },
            success: function(data){
               alert("POST SUCCESSFUL"); }
            });

Так что это лучший способ опубликовать фотографию в профиле Facebook с помощью GRAPH API, и он самый простой.

Во многих ответах я видел, что URL-адрес изображения отображается в зависимости от источника, изображения или изображения и т.д., Но это не работает. 

Использование источника, изображения или изображения приводит к (# 324) Требуется загрузить файл ошибка.

Лучший способ избежать ошибки 324.

11
sumitkanoje

Только ответ @ Thiago отвечает на вопрос загрузки данных через javascript. Я обнаружил, что API JS Facebook не охватывает эту ситуацию. 

Я также заварил и проверил свое личное решение. 

Основные шаги

  1. Получить двоичные данные изображения (я использовал холст, но также можно использовать поле ввода)
  2. Формируйте составной запрос со всеми необходимыми данными для вызова API графа
  3. Включить двоичные данные в запрос
  4. Закодируйте все в двоичном массиве и отправьте это через XHR

Код

Конверсионные утилиты

var conversions = {
  stringToBinaryArray: function(string) {
    return Array.prototype.map.call(string, function(c) {
      return c.charCodeAt(0) & 0xff;
    });
  },
  base64ToString: function(b64String) {
    return atob(b64String);
  }
};

Фрагмент публикации изображения

var DEFAULT_CALL_OPTS = {
  url: 'https://graph.facebook.com/me/photos',
  type: 'POST',
  cache: false,
  success: function(response) {
    console.log(response);
  },
  error: function() {
    console.error(arguments);
  },
  // we compose the data manually, thus
  processData: false,
  /**
   *  Override the default send method to send the data in binary form
   */
  xhr: function() {
    var xhr = $.ajaxSettings.xhr();
    xhr.send = function(string) {
      var bytes = conversions.stringToBinaryArray(string);
      XMLHttpRequest.prototype.send.call(this, new Uint8Array(bytes).buffer);
    };
    return xhr;
  }
};
/**
 * It composes the multipart POST data, according to HTTP standards
 */
var composeMultipartData = function(fields, boundary) {
  var data = '';
  $.each(fields, function(key, value) {
    data += '--' + boundary + '\r\n';

    if (value.dataString) { // file upload
      data += 'Content-Disposition: form-data; name=\'' + key + '\'; ' +
        'filename=\'' + value.name + '\'\r\n';
      data += 'Content-Type: ' + value.type + '\r\n\r\n';
      data += value.dataString + '\r\n';
    } else {
      data += 'Content-Disposition: form-data; name=\'' + key + '\';' +
        '\r\n\r\n';
      data += value + '\r\n';
    }
  });
  data += '--' + boundary + '--';
  return data;
};

/**
 * It sets the multipart form data & contentType
 */
var setupData = function(callObj, opts) {
  // custom separator for the data
  var boundary = 'Awesome field separator ' + Math.random();

  // set the data
  callObj.data = composeMultipartData(opts.fb, boundary);

  // .. and content type
  callObj.contentType = 'multipart/form-data; boundary=' + boundary;
};

// the "public" method to be used
var postImage = function(opts) {

  // create the callObject by combining the defaults with the received ones
  var callObj = $.extend({}, DEFAULT_CALL_OPTS, opts.call);

  // append the access token to the url
  callObj.url += '?access_token=' + opts.fb.accessToken;

  // set the data to be sent in the post (callObj.data = *Magic*)
  setupData(callObj, opts);

  // POST the whole thing to the defined FB url
  $.ajax(callObj);
};

Использование

postImage({
  fb: { // data to be sent to FB
    caption: caption,
    /* place any other API params you wish to send. Ex: place / tags etc.*/
    accessToken: 'ACCESS_TOKEN',
    file: {
      name: 'your-file-name.jpg',
      type: 'image/jpeg', // or png
      dataString: image // the string containing the binary data
    }
  },
  call: { // options of the $.ajax call
    url: 'https://graph.facebook.com/me/photos', // or replace *me* with albumid
    success: successCallbackFunction,
    error: errorCallbackFunction
  }
});

Дополнительный

Извлечение двоичного строкового представления изображения холста

var getImageToBeSentToFacebook = function() {
  // get the reference to the canvas
  var canvas = $('.some-canvas')[0];

  // extract its contents as a jpeg image
  var data = canvas.toDataURL('image/jpeg');

  // strip the base64 "header"
  data = data.replace(/^data:image\/(png|jpe?g);base64,/, '');

  // convert the base64 string to string containing the binary data
  return conversions.base64ToString(data);
}

Информация о том, как загрузить двоичную строку из input[type=file]

HTML5 File API, читаемый как текстовый и двоичный файл

Заметки:

  1. Конечно, есть и альтернативные подходы
    • Использование формы HTML в iframe - вы не можете получить ответ от вызова
    • Использование подхода FormData & File , но, к сожалению, в этом случае есть много несовместимостей, которые затрудняют использование процесса, и вы в конечном итоге обматываетесь вокруг несоответствий - таким образом, мой выбор был Сборка данных вручную, так как стандарты HTTP редко меняются :)
  2. Решение не требует каких-либо специальных функций HTML5.
  3. В приведенном выше примере используются jQuery.ajax , jQuery.extend , jQuery.each
6
Matyas

Да, вы можете сделать эту публикацию данных в iframe, например здесь , или вы можете использовать jQuery File Upload . Проблема в том, что вы не можете получить ответ от iframe, используя плагин, который вы можете использовать дескриптор страницы.

Пример: загрузка видео с помощью jQuery File Upload

<form id="fileupload" action="https://graph-video.facebook.com/me/photos" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="acess_token" value="user_acess_token">
    <input type="text" name="title">
    <input type="text" name="description">
    <input type="file" name="file"> <!-- name must be file -->
</form>


<script type="text/javascript">

    $('#fileupload').fileupload({
        dataType: 'json',
        forceIframeTransport: true, //force use iframe or will no work
        autoUpload : true,
        //facebook book response will be send as param
        //you can use this page to save video (Graph Api) object on database
        redirect : 'http://pathToYourServer?%s' 
    });
</script>
4
Guilherme Torres Castro

Чтобы загрузить файл с локального компьютера с помощью Javascript, попробуйте HelloJS

<form onsubmit="upload();">
     <input type="file" name="file"/>
     <button type="submit">Submit</button>
</form>

<script>
function upload(){
   hello.api("facebook:/me/photos", 'post', document.getElementById('form'), function(r){
      alert(r&&!r.error?'Success':'Failed'); 
   });
}
</script>

Демо для загрузки можно найти по адресу http://adodson.com/hello.js/demos/upload.html

2
Drew

https://stackoverflow.com/a/16439233/68210 содержит решение, которое работает, если вам нужно загрузить сами данные фотографии и не иметь URL-адреса.

2
Daniel X Moore

Это работает:

   function x(authToken, filename, mimeType, imageData, message) {
    // this is the multipart/form-data boundary we'll use
    var boundary = '----ThisIsTheBoundary1234567890';

    // let's encode our image file, which is contained in the var
    var formData = '--' + boundary + '\r\n';
    formData += 'Content-Disposition: form-data; name="source"; filename="' + filename + '"\r\n';
    formData += 'Content-Type: ' + mimeType + '\r\n\r\n';
    for (var i = 0; i < imageData.length; ++i) {
        formData += String.fromCharCode(imageData[i] & 0xff);
    }
    formData += '\r\n';
    formData += '--' + boundary + '\r\n';
    formData += 'Content-Disposition: form-data; name="message"\r\n\r\n';
    formData += message + '\r\n';
    formData += '--' + boundary + '--\r\n';

    var xhr = new XMLHttpRequest();
    xhr.open('POST', 'https://graph.facebook.com/me/photos?access_token=' + authToken, true);
    xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);

    // Solving problem with sendAsBinary for chrome
    try {
        if (typeof XMLHttpRequest.prototype.sendAsBinary == 'undefined') {
            XMLHttpRequest.prototype.sendAsBinary = function(text) {
                var data = new ArrayBuffer(text.length);
                var ui8a = new Uint8Array(data, 0);
                for (var i = 0; i < text.length; i++) ui8a[i] = (text.charCodeAt(i) & 0xff);
                this.send(ui8a);
            }
        }
    } catch (e) {}
    xhr.sendAsBinary(formData);
};
2
Thiago Tecedor

Это все еще работает. Я использую это как ниже:

var formdata= new FormData();
if (postAs === 'page'){
    postTo = pageId; //post to page using pageID
}

formdata.append("access_token", accessToken); //append page access token if to post as page, uAuth|paAuth
formdata.append("message", photoDescription);
formdata.append("url", 'http://images/image.png');

try {
    $.ajax({
        url: 'https://graph.facebook.com/'+ postTo +'/photos',
        type: "POST",
        data: formdata,
        processData: false,
        contentType: false,
        cache: false,
        error: function (shr, status, data) {
            console.log("error " + data + " Status " + shr.status);
        },
        complete: function () {
            console.log("Successfully uploaded photo to Facebook");
        }
    });
} catch (e) {
    console.log(e);
}

Я должен спросить, если вы, люди, знаете, если это целесообразно или имеет большой риск безопасности по сравнению с использованием PHP API для Facebook.

2
Carmela

Кажется, у меня похожая проблема, но решения выше не сработали.

Я использовал решение, предложенное Arrabi (просто используйте свойство url), чтобы публиковать изображения без каких-либо проблем. Мои изображения около 2-3 МБ каждый.

Когда я перенес свое приложение на другой сервер (изменив абсолютный URL моих изображений в посте), метод продолжал давать мне 324 ошибки для изображений размером более 100КБ.

Я думал, что это связано с некоторыми настройками Apache на моем конце, но когда я сменил Apache на lighttpd, проблема все еще была.

Соединения с Facebook на самом деле отображаются в моем (Apache) журнале:

69.171.234.7 - - [08/Jun/2012: 11: 35: 54 +0200] "GET /images/cards/1337701633_518192458.png HTTP/1.1" 200 2676608 "-" "facebookplatform/1.0 (+ http: // developers .facebook.com)»

69.171.228.246 - - [08/Jun/2012: 11: 42: 59 +0200] "GET /images/test5.jpg HTTP/1.1" 200 457402 "-" "facebookplatform/1.0 (+ http: //developers.facebook .com)»

69.171.228.246 - - [08/Jun/2012: 11: 43: 17 +0200] "GET /images/test4.jpg HTTP/1.1" 200 312069 "-" "facebookplatform/1.0 (+ http: //developers.facebook .com)»

69.171.228.249 - - [08/Jun/2012: 11: 43: 49 +0200] "GET /images/test2.png HTTP/1.1" 200 99538 "-" "facebookplatform/1.0 (+ http: //developers.facebook .com)»

69.171.228.244 - - [08/Jun/2012: 11: 42: 31 +0200] "GET /images/test6.png HTTP/1.1" 200 727722 "-" "facebookplatform/1.0 (+ http: //developers.facebook .com)»

Только test2.png удалось.

1
Tom Lous

Я использую следующее, чтобы поделиться фотографией (некоторые BitmapData из платформы Phaser). Вроде работает ...

// Turn data URI to a blob ready for upload.
dataURItoBlob(dataURI:string): Blob {
    var byteString = atob(dataURI.split(',')[1]);
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    return new Blob([ab], { type: 'image/jpeg' });
}

// Share the given bitmapData as a photo on Facebook
sharePhoto(accessToken: string, photo: BitmapData, message: string): void {
    // Create form data, set up access_token, source and message
    var fd = new FormData();
    fd.append("access_token", accessToken);
    fd.append("source", this.dataURItoBlob(photo.canvas.toDataURL("image/jpeg")));
    fd.append("message", message);

    var request = new XMLHttpRequest();
    var thisPtr = this;
    request.onreadystatechange = function () {
        if (request.readyState == XMLHttpRequest.DONE) {
            var json = JSON.parse(request.responseText);
            if (json.hasOwnProperty("error")) {
                var error = json["error"];
                if (error.hasOwnProperty("type")) {
                    var errorType = error["type"];
                    if (errorType === "OAuthException") {
                        console.log("Need to request more permissions!");
                    }
                }
            }
        } else if (request.readyState == XMLHttpRequest.HEADERS_RECEIVED) {

        } else if (request.readyState == XMLHttpRequest.LOADING) {

        } else if (request.readyState == XMLHttpRequest.OPENED) {

        } else if (request.readyState == XMLHttpRequest.UNSENT) {

        }
    }
    request.open("POST", "https://graph.facebook.com/me/photos", true);
    request.send(fd);
}
0
Steven Craft

Если кто-то все еще ищет, как загрузить непосредственно с холста на фотографии в Facebook, это работает для меня:

function postImageToFacebook(token, imageData, message, successCallback, errorCallback) {
  var fd = new FormData();
  fd.append("access_token", token);
  fd.append("source", imageData);
  fd.append("caption", message);

  $.ajax({
      url: "https://graph.facebook.com/me/photos?access_token=" + token,
      type: "POST",
      data: fd,
      processData: false,
      contentType: false,
      cache: false,
      success: function (data) {
        successCallback(data);
      },
      error: function (shr, status, data) {
        errorCallback(data);
      },
      complete: function (data) {
        console.log('Completed');
      }
  });
}

function dataURItoBlob(dataURI) {
  var byteString = atob(dataURI.split(',')[1]);
  var ab = new ArrayBuffer(byteString.length);
  var ia = new Uint8Array(ab);
  for (var i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i);
  }
  return new Blob([ab], {type: 'image/jpeg'});
}

Чтобы использовать его

// *IMPORTANT*
var FBLoginScope = 'publish_actions'; // or sth like 'user_photos,publish_actions' if you also use other scopes.

var caption = "Hello Facebook!";
var successCallback = ...;
var errorCallback = ...;

var data = $('#your_canvas_id')[0].toDataURL("image/jpeg");
try {
  imageData = dataURItoBlob(data);
} catch (e) {
  console.log(e);
}

FB.getLoginStatus(function (response) {
  if (response.status === "connected") {
    postImageToFacebook(response.authResponse.accessToken, imageData, caption, successCallback, errorCallback);
  } else if (response.status === "not_authorized") {
    FB.login(function (response) {
        postImageToFacebook(response.authResponse.accessToken, imageData, caption, successCallback, errorCallback);
    }, {scope: FBLoginScope});
  } else {
    FB.login(function (response) {
        postImageToFacebook(response.authResponse.accessToken, imageData, caption, successCallback, errorCallback);
    }, {scope: FBLoginScope});
  }
});

Изменено с: http://gorigins.com/posting-a-canvas-image-to-facebook-and-Twitter/

0
aunnnn