I have the code below. I want to use Post() instead of Get() because I don't want to show the username and password in the string. First I get auth and download a cookie with post(). This works fine. But then I download a xml-file with get() and the username and password is visible in the download string. How can I download latest.xml with post()? I don't get any file at all (latest.xml) if I change to post whre I have the comment (Does not work if I change to Post()).
The url is https and not http.
var apiUrl = s.getPropertyValue('apiUrl');
var apiUser = s.getPropertyValue('apiUser');
var apiPass = s.getPropertyValue('apiPass');
var anyOrders = "";
var theHTTP = new HTTP();
theHTTP.resetParameters();
theHTTP.url = apiUrl + "/wsauth?";
theHTTP.addParameter("username", apiUser);
theHTTP.addParameter("password", apiPass);
theHTTP.authScheme = HTTP.BasicAuth;
theHTTP.post(); //Works fine
while( !theHTTP.waitForFinished( 1 ) ) { }
job.log(-1, "Server response: " + theHTTP.getServerResponse().toString("UTF-8"));
if( theHTTP.finishedStatus != HTTP.Ok )
{
job.fail("The request failed: %1", theHTTP.lastError);
return;
}
var theCookie = theHTTP.getHeaderValue( HTTP.SetCookie ).toString( "UTF-8" );
if( theCookie.isEmpty() )
{
job.fail("Invalid cookie response: %1", theHTTP.lastError);
return;
}
s.log(-1, "Cookie: " + theCookie);
//Perform query to get xml file
theHTTP.addHeader( HTTP.Cookie, theCookie );
theHTTP.url = apiUrl + "/order/latest";
theHTTP.localFilePath = job.createPathWithName("latest.xml", false);
job.log(1,theHTTP.localFilePath, false);
theHTTP.get(); //Does not work if I change to Post()
job.log( 4, "Download started", 100 );
while( !theHTTP.waitForFinished( 3 ) ) {
job.log( 5, "Downloading...", theHTTP.progress() );
}
job.log( 6, "Download finished" );
//open file to read if there are any orders
var f = new File(theHTTP.localFilePath);
f.open(File.ReadOnly);
anyOrders = f.read();
f.close();
if( theHTTP.finishedStatus == HTTP.Ok && File.exists(theHTTP.localFilePath)) {
if(anyOrders == "No non-processed order found!") {
job.sendToNull( job.getPath() );
job.log( 1, "No non-processed order found! File deleted!");
} else {
job.log( 1, "Download completed successfully");
job.sendToSingle(theHTTP.localFilePath);
}
}
else {
job.fail("Download failed with the status code %1", theHTTP.statusCode);
job.sendToNull( job.getPath() );
return;
}
Related
When i inspect the response from my AJAX request to index.php, I get back some data that i want (some json, a return value i need the value of) but also a load of HTML as the index.php class is used to call a view which is responsible for loading up some HTML.
Here is the first two lines of the response:
{"returnVal":"registered"}<!DOCTYPE html>
<html lang="en">
Due to my code being MVC, i cannot just create a separate file to handle the AJAX request, so i need a way for my login.js class (where the AJAX request is generated) to go through the whole response and find the value of "returnVal" that I need. Do you know of a way I can do this?
Login.js
var loginData, urlPath;
// Allow users to log in or register
function Login() {
if(!document.getElementById("usernameField")) { // If we have no username field on this page, we are just logging in
loginData = "email=" + $("#emailField").val() + "&password=" + $("#passwordField").val() + "&action=" + "loggingIn";
urlPath = "index.php";
} else { // we are registering
loginData = "username=" + $("#usernameField").val() + "&email=" + $("#emailField").val() + "&password=" + $("#passwordField").val() + "&action=" + "register";
urlPath = "../index.php";
}
// Send the login/registration data to database
$(document).ready(function() {
$.ajax({
type: "POST",
url: urlPath,
data: loginData,
success: function (result) {
alert(result); // i need to get the value of 'returnVal' from the response
if(result.returnVal=="registered") {
document.getElementById('notification').innerHTML = "You have been registered";
} else if (result.returnVal=="username") {
document.getElementById('notification').innerHTML = "Username already taken";
} else if (result.returnVal=="email") {
document.getElementById('notification').innerHTML = "Email already taken";
} else if (result.returnVal=="notRegistered") {
document.getElementById('notification').innerHTML = "Please enter registered email";
} else if (result.returnVal=="loginFail") {
document.getElementById('notification').innerHTML = "Please enter correct password";
} else if (result.returnVal=="loggedIn") {
$('#myModal').modal('hide');
document.getElementById('loginButton').innerHTML = "Account Settings";
} else { // Something wrong, tell us
//alert(result);
}
},
error: function(xhr, status, error) {
alert(xhr.responseText);
}
})
})
}
index.php
<?php
ini_set("log_errors", 1);
require_once("Model/model.php");
require_once("Controller/controller.php");
require_once("View/view.php");
$model = new Model();
$view = new View();
$controller = new Controller($model, $view);
if(isset($_POST['action'])) {
if($_POST['action'] == "register") {
$controller->Register($_POST['username'], $_POST['email'], $_POST['password']);
echo json_encode($controller->GetReturned());
}
}
$view->Begin();
?>
Ultra simple way is just exit() after you echo the json so the view never gets sent. If this controller is never intended to render a view get rid of $view->Begin();
if(isset($_POST['action'])) {
if($_POST['action'] == "register") {
$controller->Register($_POST['username'], $_POST['email'], $_POST['password']);
echo json_encode($controller->GetReturned());
exit();
}
}
This is a (messy but still) way to extract the data you need.
But please consider my first comment. You should do it the other way round.
var result = '{"returnVal":"registered"}<!DOCTYPE html>someother grap';
var n = result.indexOf("<!DOCTYPE");
var jsonString = input.substring(0, n);
var json = JSON.parse(jsonString);
console.log(json);
// your values are here:
// json.returnVal;
This relies on the strict convention, that every return has a '
I'm using cookies to keep the user's information present on the front end. Logging them in is happening through Passport.
On login, the code sets the cookies from the user's information returned from Passport.
On logout, the cookies are unset and then /auth/logout is called to log the user.
Everything works with login/logout, but whenever I try to delete the cookies on logout, nothing happens.
This only occurs on the user.js page of my site. I am able to successfully log off from any other page
Here's my code:
Dynamically Setting the navbar
document.getElementById( 'navigation-bar' ).innerHTML =
'<ul>'+
"<li><button onclick='Home();' id='home-link'>Home</button></li>"+
"<li><a id='recipes-link' href='/recipes'>Recipes</a></li>"+
"<li><a id='festivals-link' href='/festivals'>Festivals</a></li>"+
"<li><button id='logout-button' onclick='Logout()'>Logout</button></li>"+
'</ul>';
Logout Function
function Logout() {
//Sets each cookie's expire time to 1970, forcing expire.
DeleteCookies();
//Runs Passport's 'logout' function
window.open( '/auth/logout', '_parent' );
}
Setting The Cookies
function Login () {
//Setting user parameters.
let login = { email: null, password: null };
login.email = document.getElementById( 'email' ).value;
login.password = document.getElementById( 'password' ).value;
PostRequest( '/auth/login', login, 'application/json', ( status, data ) => {
if ( status == 200 ) {
//Set 'expireTime' to current date and then add 1 hour to it.
let expireTime = new Date( Date.now() );
expireTime.setHours( expireTime.getHours() + 1 );
// Parse the return data.
let user = JSON.parse(data);
//Set cookie for each user key.
for ( const key in user ) {
document.cookie = key + '=' + user[key] + ';expires=' + expireTime.toUTCString() + ";";
}
//Open user's profile in another window using name as url.
window.open( '/user/' + user.username, '_parent' );
} else {
console.log('error');
}
});
}
Deleting The Cookies
function DeleteCookies() {
console.log( 'this is running' );
//Use old date to expire the cookies
let expire = 'expires=Thu, 01 Jan 1970 00:00:00 GMT;'
//Split each cookie into an array element.
let cookiesArray = document.cookie.split(";");
//Split the cookie to have name as the first value.
//Then use the cookie's name to expire the cookie.
for ( let cookie = 0; cookie < cookiesArray.length; cookie++ ) {
let name = cookiesArray[cookie].split( "=" )[0];
document.cookie = name + "=;" + expire;
}
}
Checking If Cookie Is Set
function IsLoggedIn() {
//If user is logged in, display the logout button.
if ( GetCookie( '_id' ) != '' ) {
document.getElementById( 'logout-button' ).style.display = 'inline-block';
}
}
user.js code
var user = {};
function UserReady() {
GetRequest( '/api/me', undefined, ( status, data ) => {
if ( status === 200 ) {
user = JSON.parse( data );
document.getElementById( 'username' ).innerHTML = "Welcome back, " + user.username;
}
});
}
All help is appreciated.
I've been trying to get an ajax alert layer to work with a POST method for several days and I can't come up with a reason for it not working. I use the same basic code to send form data through ajax with POST on other admin pages without trouble but when I try to send data that does not come from a form nothing gets to the server in $_POST.
Here's the flow of the code...
I use variables on a page like these:
$alertLayer = 1;
$autoCloseAlertLayer = 1;
$addAlertLayerCloseButton = 1;
$alertLayerMessage = $alertLayerMessage . '<h1>Test</h1><p>3rd test of the alert layer module.</p>';
$redirect = 0;
$redirectTo = 0;
and I include a script that calls a function at the bottom of the page like this:
if ($alertLayer == true)
{
echo "<script type='text/javascript' id='alertLayerScript'>Lib.ajaxAlertFunction('/Modules/AlertLayer', $autoCloseAlertLayer, $addAlertLayerCloseButton, '$alertLayerMessage', $redirect, '$redirectTo');</script>";
}
Here's the script that gets called:
Lib.ajaxAlertFunction = function (senturl, autoClose, closeButton, message, redirect, redirectTo)
{
var ajaxRequest;
try
{
ajaxRequest = new XMLHttpRequest();
}
catch (e)
{
try
{
ajaxRequest = new ActiveXObjext("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
ajaxRequest = new ActiveXObjext("Microsoft.XMLHTTP");
}
catch (e)
{
alert ("Your browser can't handle the truth!");
return false;
}
}
}
if (!senturl)
{
return false;
}
else
{
// var data = "autoClose=" + encodeURIComponent(autoClose) + "&closeButton=" + encodeURIComponent(closeButton) + "&message=" + encodeURIComponent(message) + "&redirect=" + encodeURIComponent(redirect) + "&redirectTo=" + encodeURIComponent(redirectTo);
// var data = encodeURIComponent("autoClose=" + autoClose + "&closeButton=" + closeButton + "&message=" + message + "&redirect=" + redirect + "&redirectTo=" + redirectTo);
var data = "autoClose=" + autoClose + "&closeButton=" + closeButton + "&message=" + message + "&redirect=" + redirect + "&redirectTo=" + redirectTo;
}
ajaxRequest.onreadystatechange = function()
{
if (ajaxRequest.readyState == 4 && ajaxRequest.status == 200)
{
document.getElementById('outerFrame').innerHTML += ajaxRequest.responseText;
newAlertLayer = document.getElementById('alertLayer');
var arr = newAlertLayer.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
{
eval(arr[n].innerHTML)
}
}
}
ajaxRequest.open('POST', senturl, true);
ajaxRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
ajaxRequest.send(data);
}
NOTE: I have no problem sending this data with a 'GET' method but then a long message gets cut off. I have also tried to set up the 'data' variable in several different methods that I've searched over the past 3 days with no success.
The code that expects $_POST data goes as follows:
<?php
$ROOT = $_SERVER['DOCUMENT_ROOT'];
?>
<div id="alertLayer">
<link rel="stylesheet" href="<?php $ROOT ?>/Modules/AlertLayer/alertLayer.css">
<script src="/Modules/AlertLayer/alertLayer.js"></script>
<div id="alertBlock">
<?php
foreach ($_POST as $key => $value)
{
echo "<p>" . $key . " = " . $value . "</p>";
}
foreach ($_GET as $key => $value)
{
echo "<p>" . $key . " = " . $value . "</p>";
}
?>
</div>
</div>
What am I missing? What is different from sending form data with POST and sending variables concatenated the same way?
Again, GET is working when I add the data to the url string but not sufficient, POST = no data at all received on the other end of the ajaxRequest but the rest of the request returns exactly what is expected. The $_POST data missing from the server request is currently the only problem that I cannot solve with this code.
It's looking like the request is not being sent properly but I'm unable to determine the reason. Here's a screenshot of what NETWORK tab in chrome:
Problem was a redirection (301) issued by nginx due to a missing slash at the end of the URL. This caused the POST request to be changed to GET.
Technical Details: https://softwareengineering.stackexchange.com/questions/99894/why-doesnt-http-have-post-redirect
Old approach that started the discussion:
Your Problem seems to be the encodeURIComponent() function that you're wrapping around the whole data string. This replaces the & signs with & values. If you debug this in the browsers developer console you'll see that it is not recognized as form data in the request. You should only escape the variables you're filling in.
Btw: This should also be problematic when you use GET.
This is more or less what I tried and it was sending data via POST.
window.onload=function(){
Lib.ajaxAlertFunction( '/test/target.php', 0, 0, 'Fantastic - data is being sent via POST! Amazeballs!', 0, 0 );
};
var Lib={}; /* Because I don't have the rest of `Lib` at my disposal */
Lib.ajaxAlertFunction = function ( senturl, autoClose, closeButton, message, redirect, redirectTo ) {
var ajax;/* renamed only for brevity */
try {
ajax = new XMLHttpRequest();
} catch (e) {
try {
ajax = new ActiveXObjext("Msxml2.XMLHTTP");
} catch (e) {
try {
ajax = new ActiveXObjext("Microsoft.XMLHTTP");
} catch (e) {
alert ("Your browser can't handle the truth!");
return false;
}
}
}
if ( !senturl ) return false;
else {
var data = "autoClose=" + autoClose + "&closeButton=" + closeButton + "&message=" + message + "&redirect=" + redirect + "&redirectTo=" + redirectTo;
}
ajax.onreadystatechange = function() {
if( ajax.readyState == 4 && ajax.status == 200 ) {
/*
document.getElementById('outerFrame').innerHTML += ajax.responseText;
newAlertLayer = document.getElementById('alertLayer');
var arr = newAlertLayer.getElementsByTagName('script')
for ( var n = 0; n < arr.length; n++ ) {
eval( arr[n].innerHTML );
}
*/
console.log( ajax.responseText );
}
}
ajax.open( 'POST', senturl, true );
ajax.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
ajax.send( data );
}
For the sake of the test, /test/target.php was simply:
<?php
exit( print_r($_POST,true) );
?>
and the response:
Array
(
[autoClose] => 0
[closeButton] => 0
[message] => Fantastic - data is being sent via POST! Amazeballs!
[redirect] => 0
[redirectTo] => 0
)
If it helps any, here is a basic ajax function I use in tests, perhaps something in there might be of use?
function _ajax( url, options ){
var factories=[
function() { return new XMLHttpRequest(); },
function() { return new ActiveXObject('Msxml2.XMLHTTP'); },
function() { return new ActiveXObject('MSXML2.XMLHTTP.3.0'); },
function() { return new ActiveXObject('MSXML2.XMLHTTP.4.0'); },
function() { return new ActiveXObject('MSXML2.XMLHTTP.5.0'); },
function() { return new ActiveXObject('MSXML2.XMLHTTP.6.0'); },
function() { return new ActiveXObject('Microsoft.XMLHTTP'); }
];
/* Try each factory until we have a winner */
for( var i=0; i < factories.length; i++ ) {
try { var req = factories[ i ](); if( req!=null ) { break; } }
catch( err ) { continue; }
};
var method=options.hasOwnProperty('method') ? options.method.toUpperCase() : 'POST';
var callback=options.hasOwnProperty('callback') ? options.callback :false;
if( !callback ){
alert( 'No callback function assigned - a callback is required to handle the response data' );
return false;
}
var headers={
'Accept': "text/html, application/xml, application/json, text/javascript, "+"*"+"/"+"*"+"; charset=utf-8",
'Content-type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
};
/* The main parameters of the request */
var params=[];
if( options.hasOwnProperty('params') && typeof( options.params )=='object' ){
for( var n in options.params ) params.push( n + '=' + options.params[n] );
}
/* Additional arguments that can be passed to the callback function */
var args=options.hasOwnProperty('args') ? options.args : options;
/* Assign callback to handle response */
req.onreadystatechange=function(){
if( req.readyState==4 ) {
if( req.status==200 ) options.callback.call( this, req.response, args );
else console.warn( 'Error: '+req.status+' status code returned' );
}
}
/* Execute the request according to desired method */
switch( method ){
case 'POST':
req.open( method, url, true );
for( header in headers ) req.setRequestHeader( header, headers[ header ] );
req.send( params.join('&') );
break;
case 'GET':
req.open( method, url+'?'+params.join('&'), true );
for( header in headers ) req.setRequestHeader( header, headers[ header ] );
req.send( null );
break;
}
}
/* to use */
_ajax.call( this, '/test/target.php',{ callback:console.info, method:'post',params:{'field':'value','field2':'value2'} } );
When calling the ajaxRequest the url MUST have a "/" at the end of the url (if you're not specifying an /index.php file for example).
I was using '/Modules/AlertLayer' and changing to '/Modules/AlertLayer/' has fixed the problem!
I have made an AJAX code for an on-line food store but when i am running it, it is not showing the correct output i.e. a pop up saying something went wrong always pops up. I want to know what is the problem in my code, is it something to do with the connection handlers or the JS script
Here is my index.php code
<!DOCTYPE html>
<HTML>
<HEAD>
<TITLE>AJAX</TITLE>
<SCRIPT type = "text/javascript" src = "JS/store.js"></SCRIPT>
</HEAD>
<BODY onload = "process()">
<H3>Foodstore</H3>
Enter the food you would like to order:
<INPUT type = "text" id = "user_input" placeholder = "Food Item" />
<DIV id = "output_area" />
</BODY>
</HTML>
Here is my JS code that I am using
var XML_HTTP = create_XML_HTTP_request_object();
function create_XML_HTTP_request_object() {
var XML_HTTP;
if(window.ActiveXObject) {
try {
XML_HTTP = new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {
XML_HTTP = false;
}
} else {
try {
XML_HTTP = new XMLHttpRequest();
} catch(e) {
XML_HTTP = false;
}
}
if (! XML_HTTP) {
alert('Cant create the object!!');
} else {
return XML_HTTP;
}
}
function process() {
if((XML_HTTP.readyState == 0) || (XML_HTTP.readyState == 4)) {
food = encodeURIComponent(document.getElementById("user_input").value);
url = "process.php?food=" + food;
XML_HTTP.open("GET", url, true);
XML_HTTP.onreadystatechange = handle_server_response;
XML_HTTP.send(null);
} else {
setTimeout('process()', 1000) ;
}
}
function handle_server_response() {
if(XML_HTTP.readyState == 4) {
if(XML_HTTP.status == 200) {
XML_response = XML_HTTP.responseXML;
XML_document_element = XML_response.documentElement;
message = XML_document_element.firstChild.data;
document.getElementById("output_area").innerHTML = '<SPAN style = "color:blue">' + message + '</SPAN>';
} else {
alert('Something went wrong!!');
}
}
}
Here is my PHP code that i am using
<?php
header('Content-Type: text/xml');
echo '<?XML version = "1.0" encoding = "UTF-8" standalone = "yes" ?>';
echo '<response>';
$food = $_GET['food'];
$food_array = array('tuna' , 'bacon' , 'loaf' , 'cheese' , 'pizza') ;
if(in_array($food , $food_array)) {
echo 'We do have ' . $food . ' !!';
} elseif($food == '') {
echo 'Enter a food item';
} else {
echo 'Sorry we don\'t sell ' . $food . ' !!';
}
echo '</response>';
?>
Firefox at least does NOT like the Processing Instruction
<?XML ... ?>
issues error not well-formed ... works fine with
<?xml ... ?>
However, while your code wont work, it WONT result in the alert ... the fact that your getting the alert suggests your browser can't find process.php (it should be in the same folder as your HTML file)
and an added note ... Edge doesn't like upper case HTML tags, it doesn't break, but it has a sook about them
As an alternative to the ajax functions you posted, consider the following:
function _ajax( url, options ){
var factories=[
function() { return new XMLHttpRequest(); },
function() { return new ActiveXObject('Msxml2.XMLHTTP'); },
function() { return new ActiveXObject('MSXML2.XMLHTTP.3.0'); },
function() { return new ActiveXObject('MSXML2.XMLHTTP.4.0'); },
function() { return new ActiveXObject('MSXML2.XMLHTTP.5.0'); },
function() { return new ActiveXObject('MSXML2.XMLHTTP.6.0'); },
function() { return new ActiveXObject('Microsoft.XMLHTTP'); }
];
/* Try each factory until we havea winner */
for( var i=0; i < factories.length; i++ ) {
try { var req = factories[ i ](); if( req!=null ) { break; } }
catch( err ) { continue; }
};
var method=options.hasOwnProperty('method') ? options.method.toUpperCase() : 'POST';
var callback=options.hasOwnProperty('callback') ? options.callback :false;
if( !callback ){
alert( 'No callback function assigned' );
return false;
}
var headers={
'Accept': "text/html, application/xml, application/json, text/javascript, "+"*"+"/"+"*"+"; charset=utf-8",
'Content-type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
};
/* The main parameters of the request */
var params=[];
if( options.hasOwnProperty('params') && typeof( options.params )=='object' ){
for( var n in options.params ) params.push( n + '=' + options.params[n] );
}
/* Additional arguments that can be passed to the callback function */
var args=options.hasOwnProperty('args') ? options.args : {};
/* Assign callback to handle response */
req.onreadystatechange=function(){
if( req.readyState ) {
if( req.status==200 ) options.callback.call( this, req.response, args );
else console.warn( 'Error: '+req.status+' status code returned' );
}
}
/* Execute the request according to desired method */
switch( method ){
case 'POST':
req.open( method, url, true );
for( header in headers ) req.setRequestHeader( header, headers[ header ] );
req.send( params.join('&') );
break;
case 'GET':
req.open( method, url+'?'+params.join('&'), true );
for( header in headers ) req.setRequestHeader( header, headers[ header ] );
req.send( null );
break;
}
}
You could then use it like this:
function process(){
call _ajax( this, 'process.php', { 'method':'get', 'callback':handle_server_response, params:{ 'food':food } } );
}
function handle_server_response(response){
try{/* this is not tested! */
var XML_document_element = response.documentElement ;
var message = XML_document_element.firstChild.data ;
document.getElementById("output_area").innerHTML = '<SPAN style = "color:blue">' + message + '</SPAN>' ;
}catch(err){
console.warn('oops, an error occurred: %s',err);
}
}
For future ajax requests you would only have to supply different arguments to the _ajax function rather than rewrite each time. Also, rather than popup a warning message that the user might not understand the errors get logged to the console.
Personally however I'd recommend using JSON rather than XML if there is no specific need to use XML. It's much easier to read and write programatically, requires fewer bytes to transmit and is less prone to anomolies with odd characters.
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.