I am having an intermittent problem with some Javascript code whch I cannot seem to solve and would appreciate any help with.
I have a campsite booking page which utilizes Paypal smart buttons to effect payment. In part of the Paypal Javascript 'create order' code I extract the entered customer details, populate a form using Javascript and then use fetch to post the info to a server side PHP page which inserts the info into a database.
The problem is this seems to fail 40-50% of the time ie Paypal payment is made sucessfully but the database insert appears to not be triggered.
The Javascript code is below. Any help is appreciated.
Thanks
Neville
<script>
var fname="";
var sname="";
var email="";
var mobile="";
var invoice_id="";
paypal.Buttons({
createOrder: function(data, actions) {
// This function sets up the details of the transaction, including the amount and line item details.
//1. validate form details, abort if incorrrect
if (validateForm()==false) {
alert("Incorrect Booking form data provided, aborting payment function.\r\n\r\nPlease recheck Booking form data and resubmit.");
//actions.disable();
return false;
}
//2. extract customer info from webpage
try {
email = document.forms["bookingform"]["email"].value;
invoice_id=document.forms["bookingform"]["invoice_id"].value;
fname= document.forms["bookingform"]["fname"].value;
sname = document.forms["bookingform"]["sname"].value;
mobile = document.forms["bookingform"]["mobile"].value;
if (invoice_id=="") {
invoice_id= sname.toUpperCase();
invoice_id=invoice_id+" ";
invoice_id=invoice_id.substring(0,3)+"-";
invoice_id=invoice_id+(100000 + Math.floor(Math.random() * 900000));
invoice_id=invoice_id.substring(0,10);
document.forms["bookingform"]["invoice_id"].value=invoice_id;
}
var tot_night = document.getElementById('tot_nights').innerHTML;
var tot_amt=document.getElementById("tot_amt").innerHTML;
tot_amt = tot_amt.replace("$", "");
var date_from = document.forms["bookingform"]["date_from"].value;
var date_to = document.forms["bookingform"]["date_to"].value;
var vehicle_rego = document.forms["bookingform"]["vehicle_rego"].value;
var no_adults = document.forms["bookingform"]["no_adults"].value;
var no_children = document.forms["bookingform"]["no_children"].value;
var power = document.forms["bookingform"]["power"].checked;
var tent_hire = document.forms["bookingform"]["tent_hire"].checked;
if (power=='true' || power==true) {
power ="Yes";
} else {
power="No";
}
if (tent_hire=='true' || tent_hire==true) {
tent_hire ="Yes";
} else {
tent_hire="No";
}
var street_address = document.forms["bookingform"]["street_address"].value;
var locality = document.forms["bookingform"]["locality"].value;
var package_type = document.forms["bookingform"]["package_type"].value
var voucher = document.forms["bookingform"]["voucher"].value
var notes = document.forms["bookingform"]["notes"].value
//$('#ref_fld').val(details.id);
$('#ref_fld').val('0');
} catch(err) {}
//3. create form, insert data
var formdata = new FormData();
if (formdata) {
try {
formdata.append("post_function","make_booking");
formdata.append("notes", notes);
formdata.append("invoice_id", invoice_id);
formdata.append("voucher", voucher);
formdata.append("package_type", package_type);
street_address=street_address.replace('"', '');
street_address=street_address.replace("'", "");
notes=notes.replace('"', '');
notes=notes.replace("'", "");
formdata.append("locality", locality);
formdata.append("street_address", street_address);
formdata.append("vehicle_rego",vehicle_rego);
formdata.append("trans_id",'0');
formdata.append("tot_amt",tot_amt);
formdata.append("tot_night",tot_night);
formdata.append("tent_hire",tent_hire);
formdata.append("power",power);
formdata.append("no_children",no_children);
formdata.append("no_adults",no_adults);
formdata.append("date_to",date_to);
formdata.append("date_from",date_from);
formdata.append("mobile",mobile);
formdata.append("email",email);
formdata.append("sname",sname);
formdata.append("fname",fname);
} catch(err) {}
//4. post form
const url = '/includes_macas/mysql_functions.php';
fetch(url, {
method: 'POST',
body: formdata
}).catch(function(error) {
console.log(error); // Display error if there is one.
})
}
return actions.order.create({
payer: {
name: {
given_name: fname,
surname: sname
},
email_address: email,
phone: {
phone_type: "MOBILE",
phone_number: {
national_number: mobile
}
}
},
purchase_units: [{
invoice_id: invoice_id,
amount: {
value: tot_amt
}
}],
application_context: {
shipping_preference: "NO_SHIPPING"
}
});
},
onClick: function() {
//$('#wait').show();
},
onApprove: function(data, actions) {
.......
Do not use actions.order.create() / .capture() on the client side and then record to a database, since there is no guarantee of being able to record a successful capture on your server if you do that.
Instead, for a proper server integration, create two routes -- one for 'Create Order' and one for 'Capture Order', as documented here. Your routes should return/output JSON (and only JSON). The capture route should check for success after calling PayPal and do any database writing before returning JSON to the client.
Pair your two routes with the following approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
Related
I'm trying to build a system for like & dislike posts in my project but I'm facing some issue using this on the client side , I have this form
but the problem there is no communication between server and client I don't know what I'm missing, even I click on like button I see in the client side value 1 but nothing happen on server side
the front is build with EJS view engine and this my code
<div class="row">
<button onclick="actOnPost(event);"
data-post-id="<%= user.posts[x].id %>">Like
</button>
<span id="likes-count-<%= user.posts[x].id %>"><%= user.posts[x].likes %></span>
</div>
I use this script in the index.ejs file :
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var updatePostStats = {
Like: function (postId) {
document.querySelector('#likes-count-' + postId).textContent++;
},
Unlike: function(postId) {
document.querySelector('#likes-count-' + postId).textContent--;
}
};
var toggleButtonText = {
Like: function(button) {
button.textContent = "Unlike";
},
Unlike: function(button) {
button.textContent = "Like";
}
};
var actOnPost = function (event) {
var postId = event.target.dataset.postId;
var action = event.target.textContent.trim();
toggleButtonText[action](event.target);
updatePostStats[action](postId);
axios.post('/posts/' + postId + '/act', { action: action });
};
</script>
<script src="https://js.pusher.com/4.1/pusher.min.js"></script>
<script>
var pusher = new Pusher('your-app-id', {
cluster: 'your-app-cluster'
});
var socketId;
// retrieve the socket ID on successful connection
pusher.connection.bind('connected', function() {
socketId = pusher.connection.socket_id;
});
var channel = pusher.subscribe('post-events');
channel.bind('postAction', function(data) {
// log message data to console - for debugging purposes
console.log(data);
var action = data.action;
updatePostStats[action](data.postId);
});
</script>
for the server side I have this code located in file.js:
router.post('/posts/:id/act', (req, res, next) => {
console.log('im here')
const action = req.body.action;
const counter = action === 'Like' ? 1 : -1;
Post.update({_id: req.params.id}, {$inc: {likes_count: counter}}, {}, (err, numberAffected) => {
pusher.trigger('post-events', 'postAction', { action: action, postId: req.params.id }, req.body.socketId);
res.send('');
});
});
I added console.log('Im here') to verify if there something is launching on my server side but I don't get anything, this router is not even launched
my mongodb image for posts and like button is below :
could it be possible to help on solving this or provide me a better exemple to follow ?
Best Regards,
Instead of making string or number in like, make an array, push req.user.id- user-id of the particular logged in user, and get the array length. This will give you total number of likes. In order to get toggle functionality, search that user id using findOne method and if no user found, push the id of the user who clicked the like button else pull the user id of the same user. Always print the length of the array so that while performing push or pull operations, you will get real time length of the like array.
I have a small online business where I'd like to implement an online payment system. The one that I've settled on is paypal and they have an easy to use solution found here: https://developer.paypal.com/demo/checkout/#/pattern/client
I'm currently unclear how I can allow the end user to edit how much they'd like to pay. As it is currently, upon payment, the end user can only pay 1 cent (or however much I change the string value to. Either way the value is static). I'd like to find a solution where the end user can pay as much or as little as they'd like.
The code that paypal provides is as follows:
<div class='uk-section'>
<!-- Set up a container element for the button -->
<div id="paypal-button-container"></div>
<!-- Include the PayPal JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?client-id=sd=USD"></script>
<script>
// Render the PayPal button into #paypal-button-container
paypal.Buttons({
// Set up the transaction
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '0.01'
}
}]
});
},
// Finalize the transaction
onApprove: function(data, actions) {
return actions.order.capture().then(function(details) {
// Show a success message to the buyer
alert('Transaction completed by ' + details.payer.name.given_name + '!');
});
}
}).render('#paypal-button-container');
</script>
</div>
As you can see the value amount is a string key pair within an object, within another object, in an array, in an object, that is an input parameter for a return statement inside a function. Any guidance into finding a working solution would be greatly appreciated.
Just put your amount in a input field for the user to enter his/her value and use that to transfer over to the PayPal API..
With HTML just use an Input field for the amount for the user.
Using REST API V2 CLIENT SIDE CODE with JavaScript and a mix of Jquery
// Render the PayPal button into #paypal-button-container
// by - Using PayPal REST V2 API
paypal
.Buttons({
style: {
layout: 'horizontal',
color: 'gold',
shape: 'pill',
label: 'checkout',
size: 'responsive',
tagline: 'true',
},
// Set up the transaction
createOrder: function(data, actions) {
$('#paypalmsg').hide();
$('#transmsg').html('<b>'+'WAITING ON AUTHORIZATION...'+'</b>');
$('#chkoutmsg').hide()
return actions.order.create({
purchase_units: [{
description: 'GnG Order',
amount: {
value: cartTotal (HERE IS WHERE YOUR USER INPUT AMOUNT WOULD GO AS
A VARIABLE, you will have to make it a VAR using JavaScript or
Jquery, I.E. UserVal = $(USERSelect).val();)
}
}],
application_context: {
shipping_preference: 'NO_SHIPPING'
}
});
},
// Finalize the transaction
onApprove: function(data, actions) {
return actions.order.get().then(function(orderDetails) {
// Show a success message to the buyer
$('#transmsg').html('<b>' + 'AUTHORIZED...' + '</b>');
$('#transmsg').append('<br>'+'Transaction completed by: ' +
orderDetails.payer.name.given_name +' '+
orderDetails.payer.name.surname + '<br>' + "Order Id: " +
orderDetails.id + '<br>' + 'Status: ' + orderDetails.status+'!' +
'<br>'+ 'Thank You For Your Order'+ '<br>');
if (orderDetails.status === "APPROVED") {
window.setTimeout(function() {}, 500)
$('#transmsg').append('<b>' + 'Sending Order...Please Wait' +
'</b>'+'<br>');
// do some form clean up before the email post
var getId = '#'+ $('span:contains("Market")').attr('id');
var getmrktDiv = '#'+ $(getId).offsetParent().attr('id');
var mrktchkId = '#'+
$(getmrktDiv).closest(getmrktDiv).find(".chkbox").attr('id');
var mrktpriceId = '#'+
$(getmrktDiv).closest(getmrktDiv).find(".price").attr('id');
var chkboxId = "#chk6";
var hidpriceId = "#pricef";
var marketLocation = $(mrktchkId);
/* Lets do a little Validation */
/* This is WHERE you do any form validation (without using PayPal
built-in Validation function */
if (marketLocation.length > 0 ) {
var checked = $(mrktchkId).prop('checked');
if (!checked) {
var storedVal = $(mrktpriceId).val();
if ($(mrktpriceId+':not([data-val])')) {
$(mrktpriceId).attr("data-val", storedVal);
}
$(mrktpriceId).val("");
}
}
$('#transid').val(orderDetails.id); (PAYPAL RETURN TRANSACTION ID,
ADD TO FORM BEFORE POST)
$('#orderstat').val(orderDetails.status); (PAYPAL ORDER STATUS,
ADD TO FORM BEFORE POST)
$('#orderform').submit(); (SEND EMAIL TO BUSINESS EMAIL AFTER
TRANSACTION IS AUTHORIZED)
}
});
if (details.error === 'INSTRUMENT_DECLINED') {
$('#transmsg').html('<b>' + 'TRANSACTION WAS DECLINED'+'</b>');
$('#transmsg').fadeIn('slow').delay(3000).fadeOut('slow', function() {
$('#paypalmsg').show();
$('#chkoutmsg').show();
$('#transmsg').empty();
});
return actions.restart();
};
},
onCancel: function(data) {
$('#transmsg').html('<b>' + 'YOUR TRANSACTION WAS CANCELLED' + '</b>');
$('#transmsg').fadeIn('slow').delay(3000).fadeOut('slow', function() {
$('#paypalmsg').show();
$('#chkoutmsg').show();
$('#transmsg').empty();
});
}
}).render('#paypal-button-container');
</script>
Hope this helps you get in the right direction.
I have a page that allows users to select contact names and details from their mobile device, what I am trying to do is then add those details to a mysql database using ajax.
Original code to get contact details from device.
function select_a_contact()
{
intel.xdk.contacts.chooseContact();
}
document.addEventListener('intel.xdk.contacts.choose', function(evt){
if (evt.success == true)
{
var contactID = evt.contactid;
//this function retrieves information of a contact based on its id.
var contactInfo = intel.xdk.contacts.getContactData(contactID);
var firstName = contactInfo.first;
var lastName = contactInfo.last;
var phoneNumbers = contactInfo.phones;
var emails = contactInfo.emails;
var address = contactInfo.addresses;
alert(firstName + lastName);
}
else if (evt.cancelled == true)
{
alert("Choose Contact Cancelled");
}
});
Here is my modified code where I have added some code to send the contact details to a php page. when I select a contact I don't get get any errors, but the Alert doesn't trigger so i am assuming that my code isn't working. If i use the ajax code in a form environment it works perfectly, i have tried writing this several different ways but the ajax code doesn't seem to trigger.
function select_a_contact()
{
intel.xdk.contacts.chooseContact();
}
document.addEventListener('intel.xdk.contacts.choose', function(evt){
if (evt.success == true)
{
var contactID = evt.contactid;
//this function retrieves information of a contact based on its id.
var contactInfo = intel.xdk.contacts.getContactData(contactID);
var firstName = contactInfo.first;
var lastName = contactInfo.last;
var phoneNumbers = contactInfo.phones;
var emails = contactInfo.emails;
var address = contactInfo.addresses;
$.ajax({
type: "POST",
url: "http://www.domian.co.uk/app/build.php",
data: {
var firstName = contactInfo.first;
var lastName = contactInfo.last;
var phoneNumbers = contactInfo.phones;
var emails = contactInfo.emails;
var address = contactInfo.addresses;
},
success: function(){
alert(firstName);
}
});
alert(firstName + lastName);
}
else if (evt.cancelled == true)
{
alert("Choose Contact Cancelled");
}
});
Your data portion is wrong. Try this instead:
data: {
firstName: firstName,
lastName: lastName,
phoneNumbers: phoneNumbers,
emails: emails,
address: address
},
... or ...
data: {
firstName: contactInfo.first,
lastName: contactInfo.last,
phoneNumbers: contactInfo.phones,
emails: contactInfo.emails,
address: contactInfo.addresses
},
Using the second you can get rid of all the new variable declarations, clean your code up a bit. You technically don't need them.
I'm currently implementing a web smartphone application with Phonegap. On this application, users can post images they take with the phone camera on Facebook. This feature has been succesfully implemented only using javascript, by sending a base 64 encoded image. Now, I want to implement the same feature using Twitter.
I found some very interesting blog posts about this and I'm already be able to update the user status only using javascript... but I can't post images too using the update_with_media Twitter web service.
According too this post, someone says it's impossible to implement this operation without using a server side code (like a php script for example).
So my question is : is it possible to use the update_with_media Twitter web service only with javascript ?
I send you my code to have an overview of the current solution. I've taken this article as working base : http://oodlestechnologies.com/blogs/Twitter-integration-on-PhoneGap-using-ChildBrowser-and-OAuth-for-iOS-and-Android-Platforms
Here is my HTML code.
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="../js/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../cordova-2.5.0.js"></script>
<script type="text/javascript" src="../js/childBrowser/childbrowser.js"></script>
<script type="text/javascript" src="../js/helpers/jsOAuth-1.3.6.js"></script>
<script type="text/javascript" src="../js/helpers/twitter.js"></script>
</head>
<body>
<h4>Oodles Twitter App</h4>
<table border="1">
<tr>
<th>Login using Twitter</th>
<th>
<button id="loginBtn" onclick="Twitter.init();">Login</button>
<button id="logoutBtn" onclick="logOut();">Logout</button>
</th>
</tr>
<tr id="tweetText">
<td colspan="2"><textarea id="tweet"></textarea></td>
</tr>
<tr id="tweetBtn">
<td colspan="2" align="right">
<button id="tweeter" onclick="Twitter.tweet();">Tweet</button>
</td>
</tr>
<tr><td colspan="2"><div id="welcome">Please Login to use this app</div></td></tr>
</table>
<br/>
<br/>
<button onclick="javascript:location.reload();">Recharger la page</button>
</body>
</html>
Here is my twitter.js code : (The point is in the post method)
$(document).ready(function() {
document.addEventListener("deviceready", onDeviceReady, false);
});
function onDeviceReady() {
var root = this;
cb = window.plugins.childBrowser;
if (!localStorage.getItem(twitterKey)) {
$("#loginBtn").show();
$("#logoutBtn").hide();
$("tweetBtn").hide();
$("tweetText").hide();
}
else {
$("#loginBtn").hide();
$("#logoutBtn").show();
$("tweetBtn").show();
$("tweetText").show();
}
if (cb != null) {
cb.onLocationChange = function(loc) {
root.locChanged(loc);
};
cb.onClose = function() {
root.onCloseBrowser()
};
cb.onOpenExternal = function() {
root.onOpenExternal();
};
}
}
function onCloseBrowser() {
console.log("onCloseBrowser!");
}
function locChanged(loc) {
console.log("locChanged!");
}
function onOpenExternal() {
console.log("onOpenExternal!");
}
// Consumer key : ...
// Consumer secret : ...
// GLOBAL VARS
var oauth; // It Holds the oAuth data request
var requestParams; // Specific param related to request
var options = {consumerKey: '...', consumerSecret: '...', callbackUrl: "http://www.google.fr"};
var twitterKey = "twtrKey"; // This key is used for storing Information related
var Twitter = {
init: function() {
// Apps storedAccessData , Apps Data in Raw format
var storedAccessData, rawData = localStorage.getItem(twitterKey);
// here we are going to check whether the data about user is already with us.
if (localStorage.getItem(twitterKey) !== null) {
// when App already knows data
storedAccessData = JSON.parse(rawData); //JSON parsing
//options.accessTokenKey = storedAccessData.accessTokenKey; // data will be saved when user first time signin
options.accessTokenSecret = storedAccessData.accessTokenSecret; // data will be saved when user first first signin
// javascript OAuth take care of everything for app we need to provide just the options
oauth = OAuth(options);
oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
function(data) {
var entry = JSON.parse(data.text);
console.log("USERNAME: " + entry.screen_name);
}
);
}
else {
// we have no data for save user
oauth = OAuth(options);
oauth.get('https://api.twitter.com/oauth/request_token',
function(data) {
requestParams = data.text;
cb.showWebPage('https://api.twitter.com/oauth/authorize?' + data.text); // This opens the Twitter authorization / sign in page
cb.onLocationChange = function(loc) {
Twitter.success(loc);
}; // Here will will track the change in URL of ChildBrowser
},
function(data) {
console.log("ERROR: " + JSON.stringify(data));
}
);
}
},
/*
When ChildBrowser's URL changes we will track it here.
We will also be acknowledged was the request is a successful or unsuccessful
*/
success: function(loc) {
// Here the URL of supplied callback will Load
/*
Here Plugin will check whether the callback Url matches with the given Url
*/
if (loc.indexOf("http://www.google.fr") >= 0) {
// Parse the returned URL
var index, verifier = '';
var params = loc.substr(loc.indexOf('?') + 1);
params = params.split('&');
for (var i = 0; i < params.length; i++) {
var y = params[i].split('=');
if (y[0] === 'oauth_verifier') {
verifier = y[1];
}
}
// Here we are going to change token for request with token for access
/*
Once user has authorised us then we have to change the token for request with token of access
here we will give data to localStorage.
*/
oauth.get('https://api.twitter.com/oauth/access_token?oauth_verifier=' + verifier + '&' + requestParams,
function(data) {
var accessParams = {};
var qvars_tmp = data.text.split('&');
for (var i = 0; i < qvars_tmp.length; i++) {
var y = qvars_tmp[i].split('=');
accessParams[y[0]] = decodeURIComponent(y[1]);
}
$('#oauthStatus').html('<span style="color:green;">Success!</span>');
$('#stage-auth').hide();
$('#stage-data').show();
oauth.setAccessToken([accessParams.oauth_token, accessParams.oauth_token_secret]);
// Saving token of access in Local_Storage
var accessData = {};
accessData.accessTokenKey = accessParams.oauth_token;
accessData.accessTokenSecret = accessParams.oauth_token_secret;
// Configuring Apps LOCAL_STORAGE
console.log("TWITTER: Storing token key/secret in localStorage");
localStorage.setItem(twitterKey, JSON.stringify(accessData));
oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
function(data) {
var entry = JSON.parse(data.text);
console.log("TWITTER USER: " + entry.screen_name);
$("#welcome").show();
document.getElementById("welcome").innerHTML = "welcome " + entry.screen_name;
successfulLogin();
// Just for eg.
app.init();
},
function(data) {
console.log("ERROR: " + data);
}
);
// Now we have to close the child browser because everthing goes on track.
window.plugins.childBrowser.close();
},
function(data) {
console.log(data);
}
);
}
else {
// Just Empty
}
},
tweet: function() {
var storedAccessData, rawData = localStorage.getItem(twitterKey);
storedAccessData = JSON.parse(rawData); // Paring Json
options.accessTokenKey = storedAccessData.accessTokenKey; // it will be saved on first signin
options.accessTokenSecret = storedAccessData.accessTokenSecret; // it will be save on first login
// javascript OAuth will care of else for app we need to send only the options
oauth = OAuth(options);
oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
function(data) {
var entry = JSON.parse(data.text);
Twitter.post();
}
);
},
/*
We now have the data to tweet
*/
post: function() {
alert('Post !');
var theTweet = $("#tweet").val(); // You can change it with what else you likes.
oauth.post('https://upload.twitter.com/1/statuses/update_with_media.json',
{
'status': theTweet,
'media': //HERE IS THE PROBLEM, WHAT TO DO HERE ?
}, "multipart/form-data",
function(data)
{
alert('Data 1 !');
console.log('------Data1 : ' + data);
var entry = JSON.parse(data.text);
console.log(entry);
done();
},
function(data) {
//var json_result = JSON.parse(data);
//alert(json_result.text.error);
var entry = JSON.stringify(data);
console.log('------Data2 : ' + entry);
}
);
}
}
function done() {
alert("OKKK !");
$("#tweet").val('');
}
function successfulLogin() {
$("#loginBtn").hide();
$("#logoutBtn,#tweet,#tweeter,#tweetBtn,#tweetText").show();
}
function logOut() {
//localStorage.clear();
window.localStorage.removeItem(twitterKey);
document.getElementById("welcome").innerHTML = "Please Login to use this app";
$("#loginBtn").show();
$("#logoutBtn,#tweet,#tweeter,#tweetText,#tweetBtn").hide();
}
After many tests (sending a base64 image, sending a blob, sending a binary file, ...) here is the return message from Twitter I have :
{\"errors\":[{\"message\":\"Internal
error\",\"code\":131}]}","xml":"","requestHeaders":{"Content-Type":"multipart/form-data"},"responseHeaders":{"date":"Fri,
19 Apr 2013 15:45:28
GMT","content-encoding":"deflate","strict-transport-security":"max-age=631138519","status":"500
Internal Server
Error","server":"tfe","content-type":"application/json;
charset=utf-8","version":"HTTP/1.1"}}
A "solution" (by send a blob) have been posted on the Twitter dev forum but not working for me : dev.twitter.com/discussions/6969
Does anyone want to implement the same feature or have a solution ? Thank you !
------ EDITED :
I just want to use Javascript and I don't want to implement any server-side solution (no PHP, C#, Java...).
According to the docs, Twitter requires the multipart/form-data enctype, which means a base64 string isn't going to work.
Unlike POST statuses/update, this method expects raw multipart data. Your POST request's Content-Type should be set to multipart/form-data with the media[] parameter ~ https://dev.twitter.com/docs/api/1/post/statuses/update_with_media
However, you could host an endpoint that takes base64, converts it to a real file, and forwards the request to Twitter. For example (untested):
<?php
$base64 = $_POST['image'];
$data = base64_decode( $base64 );
// Make name unique to avoid conflicts.
$temp_file = uniqid() . $_POST['name'];
// Save the file to a temp location.
file_put_contents( $temp_file, $data );
$temp_info = pathinfo( $temp_file );
$temp_type = $temp_info['extension'];
$temp_name = basename( $temp_file, '.' . $temp_type );
// OAuth library recommended by Twitter: https://github.com/themattharris/tmhOAuth
// See original: https://github.com/themattharris/tmhOAuth-examples/blob/master/images.php
require 'tmhOAuth.php';
require 'tmhUtilities.php';
$tmhOAuth = new tmhOAuth( array(
'consumer_key' => $_POST['consumer_key'],
'consumer_secret' => $_POST['consumer_secret'],
'user_token' => $_POST['user_token'],
'user_secret' => $_POST['user_secret'],
));
// note the type and filename are set here as well
// Edit: Not sure if the `type` and `filename` params are necessary.
$params = array( 'media[]' => "#{$temp_file};type={$temp_type};filename={$temp_name}" );
$code = $tmhOAuth->request( 'POST', $tmhOAuth->url( '1/status/update_with_media' ),
$params,
true, // use auth
true // multipart
);
// Remove temp file.
unlink( $temp_file );
if ( $code == 200 ) {
tmhUtilities::pr( json_decode( $tmhOAuth->response['response'] ) );
}
tmhUtilities::pr( htmlentities( $tmhOAuth->response['response'] ) );
?>
And you might call it like:
$.ajax({
// You'll want to use https to protect the oauth info.
url: "https://mysite.com/proxy.php",
type: "POST",
data: {
image: "base64 data...",
name: "foo.png",
consumer_key: options.consumerKey,
consumer_secret: options.consumerSecret,
user_token: options.accessTokenKey,
user_secret: options.accessTokenSecret
},
success: function( data ) {
console.log( data );
}
});
For anyone trying to post images to Twitter using client JS, I was able to post to twitter using the solution by gary-buynary-co-za (https://github.com/bytespider/jsOAuth/pull/11) at the end of this forum. Pretty much ended up using Phonegap FileTransfer and FileTransferOptions objects for transferring image to twitter api, but used jsOAuth for preparing FileTransferOptions headers and signatures. The solution could definitely be cleaned up though.
I am debugging code written by someone else - I am also a newbie at Ajax and JS. The code shown below uses Ajax (Prototype JavaScript framework, version 1.6.0.1) to submit a simple contact form and update the page with the response. It works perfectly with IE8 and fails with Firefox. I have traced the failure to the post parameters. The target file, mail.php, is not receiving any POST parameters when Firefox is the browser. Not just the values are missing - the params are not defined in the post. The URL is valid. The form, the Ajax JS files and the mail.php script are all on the same domain.
I have tried variations on defining var params as shown in several other Stack Overflow posts (inline, different assignment methods, etc). All produced the same results as the code below.
Any clue what is wrong?
FF results
Please try again. responseText='', url='http://domain.com/builder/mail.php',
form_name='dom', form_message='testing', form_email='dom#domain.com',
form_to='info#domain.com'
IE8 results
Message Sent!
JS function
function sendForm(F)
{
$("contact_form").hide();
$("ajax-loader").show();
var url = site_url+'mail.php';
var form_message = escape($("message").value);
var form_name = escape($("name").value);
var form_address = escape($("address").value);
var form_phone = escape($("phone").value);
var form_email = escape($("email").value);
var form_how_learn = escape($("how_learn").value);
var form_to = escape($("to").value);
var params = {message: form_message,
name: form_name,
address: form_address,
phone: form_phone,
email: form_email,
how_learn: form_how_learn,
to: form_to};
var ajax = new Ajax.Updater(
'contact_form',
url,
{
method: 'post',
parameters: params,
onComplete: function (response)
{
$("ajax-loader").hide();
if (response.responseText == "ok")
{
$("contact_form").innerHTML = "<p style=\"color:green;\">Message Sent!</p>";
$("contact_form").show();
}
else
{
// Debug code added
$("contact_form").innerHTML = "<p style=\"color:red;\">Please try again."+
" responseText='"+response.responseText+"',"+
" url='"+url+"',"+
" form_name='"+form_name+"',"+
" form_message='"+form_message+"',"+
" form_email='"+form_email+"',"+
" form_to='"+form_to+"'"+
"</p>";
$("contact_form").show();
}
},
onFailure: function ()
{
$("ajax-loader").hide();
$("contact_form").innerHTML = "<p style=\"color:red;\">Please try again.</p>";
$("contact_form").show();
}
}
);
return false;
}