Facebook Graph API - upload photo using JavaScript

前端 未结 13 1269
温柔的废话
温柔的废话 2020-11-27 11:03

Is it possible to upload a file using the Facebook Graph API using javascript, I feel like I\'m close. I\'m using the following JavaScript

var params = {};
         


        
相关标签:
13条回答
  • 2020-11-27 11:36

    EDIT: this answer is (now) largely irrelevant. If your image is on the web, just specify the url param as per the API (and see examples in other answers). If you would like to POST the image content to facebook directly, you may want to read this answer to gain understanding. Also see HTML5's Canvas.toDataUrl().

    The API says: "To publish a photo, issue a POST request with the photo file attachment as multipart/form-data."

    FB is expecting that the bytes of the image to be uploaded are in the body of the HTTP request, but they're not there. Or to look at it another way - where in the FB.api() call are you supplying the actual contents of the image itself?

    The FB.api() API is poorly documented, and doesn't supply an example of an HTTP POST which includes a body. One might infer from the absence of such an example that it doesn't support this.

    That's probably OK - FB.api() is using something called XmlHttpRequest under the covers which does support including a body ... look it up in your favourite JavaScript reference.

    However, you'll still have 2 sub-problems to solve:

    1. how to prepare the image bytes (and rest of the request) as multipart/form-data; and
    2. getting the bytes of the image itself

    (incidentally, the need to encode the message body is probably what the PHP setFileUploadSupport(true) method is for - tell the facebook object to encode the message body as multipart/form-data before sending)

    But it's a bit meessier than that

    Unfortunately, sub-problem '2' may bite you - there is no way (last time I looked) to extract the bytes of an image from the browser-supplied Image object.

    If the image to be uploaded is accessible via a URL, you could fetch the bytes with XmlHttpRequest. Not too bad.

    If the image is coming from the user's desktop, your probable recourse is to offer the user a:

     <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> 
    

    (notice that source references the name given to the file-upload widget)

    ... and hope that FB anticipated receiving the data in this manner (try it with a static HTML form first, before coding it up dynamically in JS). One might infer that in fact it would, since they don't offer another means of doing it.

    0 讨论(0)
  • 2020-11-27 11:38

    Photos can be uploaded to facebook profile using Ajax as follows.

    $.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"); }
                });
    

    So this is the best way to post photo to a facebook profile with GRAPH API and is the simple one.

    In many answer i have seen that image url is shwon by the source,picture or image etc but that doesn't works.

    The use of of source,picture or image leads to a (#324) Requires upload file error .

    Best way to avoid the 324 error.

    0 讨论(0)
  • 2020-11-27 11:40

    i used @Владимир Дворник code with some modification, I had the same issue and with this code it worked very well:

            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);
                }
    
            });
    
    0 讨论(0)
  • 2020-11-27 11:40

    This works:

       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);
    };
    
    0 讨论(0)
  • 2020-11-27 11:45

    In case anyone still looking for how to upload directly from canvas to Facebook photos, this works for me:

    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'});
    }
    

    To use it

    // *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});
      }
    });
    

    Modified from: http://gorigins.com/posting-a-canvas-image-to-facebook-and-twitter/

    0 讨论(0)
  • 2020-11-27 11:47

    Only @Thiago's answer is answering the question of uploading data via javascript. I've found that the Facebook JS API doesn't cover this situation.

    I've also brew & tested my personl solution.

    Main steps

    1. Get the binary data of the image (I've used a canvas, but using an input box is possible as well)
    2. Form a multipart request with all necesarry data for the graph API call
    3. Include the binary data in the request
    4. Encode everything in a binary array and send it so via XHR

    Code

    Conversion utilities

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

    Image posting snippet

    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);
    };
    

    Usage

    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
      }
    });
    

    Extra

    Extracting the binary string representation of a canvas image

    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);
    }
    

    Information on how to load the binaryString from an input[type=file]

    HTML5 File API read as text and binary

    Notes:

    1. There are of course alternative approaches as well
      • Using an HTML form in an iframe - you cannot get the response from the call
      • Using a FormData & File approach, but unfortunately in this case there are a lot of incompatilities which make the process harder to use, and you would end up duct-taping around the inconsistencies - thus my choice was manual data assembly since HTTP standards rarely change :)
    2. The solution does not require any special HTML5 features.
    3. The above example uses jQuery.ajax, jQuery.extend, jQuery.each
    0 讨论(0)
提交回复
热议问题