cURL PHP: uploading photo to Instagram - php

I authorized to Instagram, got all cookies, etc.
Now it's time to make request at https://www.instagram.com/create/upload/photo/.
In Chrome's inspector I see that browser sends these post data (where the binary photo is probably blob):
upload_id: 1539936226445
photo: (binary)
media_type: 1
And custom headers:
x-csrftoken: ACCESS_TOKEN_THAT_I_ALREADY_WROTE_INTO_THE_FILE
x-instagram-ajax: 723425780848
x-requested-with: XMLHttpRequest
But when I do the same request using cURL (passing posts and header that I wrote upper), I get 403 Forbidden, but should get 200 Ok with JSON response.
Here is how I make request:
$this->headers['csrftoken'] = $this->getFileData('csrftoken');
// generate upload_id for post field
$uploadId = number_format(round(microtime(true) * 1000), 0, '', '');
// generate binary from image file (maybe not correct)
$file_bin = fopen($file, 'rb');
// all my post fields
$params = array(
'upload_id' => $uploadId,
'photo' => $file_bin,
'media_type' => '1',
);
$ch = curl_init('https://www.instagram.com/create/upload/photo/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, true);
// custom headers
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'x-csrftoken: '.$this->headers['csrftoken'],
'x-instagram-ajax: '.$this->headers['x-instagram-ajax'],
'x-requested-with: '.$this->headers['x-requested-with']
));
curl_setopt($ch, CURLOPT_POST, true);
// post fields
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookieFile);
curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookieFile);
curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
// and finally get 403 forbidden instead of 200 ok with json response
$result = curl_exec($ch);
curl_close($ch);
return $result;
Does anybody know where the problem can hide?
Thanks so much for the help!

You should pass your cookies data, or start another session inside the code and send the cookie and the csrftoken of the session.

Related

How to stop PHP cURL upload inserting "Boundary" into the "Content-Type" field?

I'm using the below code to upload an MP4 file to a web service, using PHP cURL.
I've specified the 'Content-Type' as 'video/mp4', in CURLOPT_HTTPHEADER.
Unfortunately, having uploaded the file, the 'Content-Type' stored for it in the service displays as: "content_type":"video/mp4; boundary=----WebKitFormBoundaryfjNZ5VkJS8z3CB9X"
As you can see, the 'boundary' has been inserted into the 'content_type'.
When I then download the file, it fails to play, with a 'file unsupported/file extension incorrect/file corrupt' message.
$authorization = "Authorization: Bearer [token]";
$args['file'] = curl_file_create('C:\example\example.mp4','video/mp4','example');
$url='[example web service URL]';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: multipart/form-data', 'Accept: application/vnd.mendeley-content-ticket.1+json', $authorization));
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS , $args);
$response = curl_exec($ch); // URL encoded output - needs to be URL encoded to get the HREF link header
curl_close($ch);
Would be extremely grateful for any help, advice or pointers!
Maybe the API doesn't expects a POST multipart, but the actual contents in the body itself:
Ref: How to POST a large amount of data within PHP curl without memory overhead?
You need to use PUT method for the actual contents of the file to go inside the body - if you use POST, it will try to send as a form.
$authorization = "Authorization: Bearer [token]";
$file = 'C:\example\example.mp4';
$infile = fopen($file, 'r');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.mendeley.com/file_contents");
curl_setopt($ch, CURLOPT_PUT, 1 ); // needed for file upload
curl_setopt($ch, CURLOPT_INFILESIZE, filesize($file));
curl_setopt($ch, CURLOPT_INFILE, $infile);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST' );
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: video/mp4', 'Accept: application/vnd.mendeley-content-ticket.1+json', $authorization));
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec ($ch);
I have the same problem calling a Openai API from PHP curl.
I send options: Content-Type and Authorization (with my api key) but, when I send request, I receive this error:
Invalid Content-Type header (application/json; boundary=------------------------66a0b850cd1421c8), expected application/json
I tried to use some of your options with no success.
I cannot remove the boundary parameter added automatically.

Why i can't get a right response from server using Curl?

I need to get response from server using curl, but I can't.
The site: https://www.investing.com/holiday-calendar/
I can get that calendar using get request, but I need a list with custom dates. That mean I should use that datepicker. So when I press "apply" it sent post request with data I needed to get. (see the screenshots)
The DatePicker:
A post request with JSON response:
Code:
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
define('DIR', __DIR__);
$user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'Traider';
$cookie = dirname(__FILE__).DIRECTORY_SEPARATOR.'init_cookie.txt';
$f = fopen('init_deb.txt', 'w');
$ch = curl_init();
$getUrl = 'https://www.investing.com/holiday-calendar/';
$postUrl = 'https://www.investing.com/holiday-calendar/Service/getCalendarFilteredData';
$dateFrom='2017-01-14';
$dateTo='2017-12-31';
$limit_from = 0;
$params = [
'dateFrom' => $dateFrom,
'dateTo' => $dateTo,
'county' => '',
'limit_from' => $limit_from
];
curl_setopt($ch, CURLOPT_URL, $postUrl);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie);
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_STDERR, $f);
$response = curl_exec($ch);
fclose($f);
curl_close($ch);
echo $response;
Step 1. I sent a get request, save cookies.
Step 2. I sent a post request changing $getUrl -> $postUrl. I always get the main page. Why I can't get JSON response?
after a bit of testing, the big secret is that they refuse requests that dont have the X-Requested-With:XMLHttpRequest header attached. attach that (using CURLOPT_HTTPHEADER), and you dont even need a cookie session. i guess its part of some XSS protection scheme.
working example code using hhb_curl from https://github.com/divinity76/hhb_.inc.php/blob/master/hhb_.inc.php :
<?php
declare(strict_types=1);
require_once('hhb_.inc.php');
$hc=new hhb_curl();
$hc->_setComfortableOptions();
$hc->setopt_array(array(
CURLOPT_POST=>true,
CURLOPT_POSTFIELDS=>http_build_query(array(
'dateFrom'=>'2017-01-28',
'dateTo'=>'2017-01-28',
'country'=>'',
'limit_from'=>'0'
)),
CURLOPT_HTTPHEADER=>array(
'X-Requested-With:XMLHttpRequest'
)
));
$hc->exec('https://www.investing.com/holiday-calendar/Service/getCalendarFilteredData');
hhb_var_dump($hc->getResponseBody());

How do I fix this Bitly oAuth 'single header' error?

Context: I have a WordPress plugin that allows users to authenticate with Bitly so that they can use link shortening features if they desire to do so.
Bitly requires one callback URL to be stored in the app settings, so I created a standalone script on my server that processes the authentication process. The overall handshake actually looks something like this:
The user clicks a link taking them to the Bitly authorization page for my app.
If they agree, they are forwarded to my script with a code.
My script exchanges that code to Bitly for another code.
Once the codes are all acquired, it reaches out to the user's domain to store the codes and to retreive the URL of the options page on that user's URL so that we can redirect the user back home.
We then redirect the user back to the options page that they had just clicked away from.
Problem: However, a very small handful of users are getting the following error just prior to the authentication process being complete:
Warning: Header may not contain more than a single header, new line
detected in /home/warfarep/public_html/bitly_oauth.php on line 72.
Sample Code:
function sw_file_get_contents_curl($url){
$ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($ch, CURLOPT_FAILONERROR, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
$cont = #curl_exec($ch);
$curl_errno = curl_errno($ch);
curl_close($ch);
if ($curl_errno > 0) {
return 0;
}
return $cont;
}
// Check if this is the first pass and we have the generic code
if(isset($_GET['code'])):
// Retreive the information
$code = $_GET['code'];
$client_ID = 'blahblahblah';
$client_secret = 'blahblahblah';
$redirect_url = 'blahblahblah';
$state = $_GET['state'];
$url = 'https://api-ssl.bitly.com/oauth/access_token';
$fields = array(
'code' => urlencode($code),
'client_id' => urlencode($client_ID),
'client_secret' => urlencode($client_secret),
'redirect_uri' => urlencode($redirect_url),
'state' => urlencode($state)
);
//url-ify the data for the POST
foreach($fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
rtrim($fields_string, '&');
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_HTTPHEADER, array('Accept: application/json'));
//execute post
$response = curl_exec($ch);
//close connection
curl_close($ch);
$response = json_decode($response , true);
$ajax_url = $state .= '?action=sw_bitly_oauth&access_token='.$response['access_token'].'&login='.$response['login'];
$wp_response = sw_file_get_contents_curl($ajax_url);
$wp_response = rtrim($wp_response , '0');
header('Location: '.$wp_response);
^^^^^^ This is line 72 from the error message
endif;
Question: Is there anything that you can see that would prevent headers from already being sent prior to the redirect on line 72? How do I fix this Bitly oauth "single header" error? Thanks!

How to get info on sent PHP curl request

I'm trying to debug a curl request to a webservice 'getToken' endpoint.
I'm not 100% confident that the URL and the auth info is getting written in to the curl handle correctly.
I'm trying to use curl_getinfo($ch, CURLINFO_HEADER_OUT); to capture the sent request, but it doesn't give me much info. Is there a way to get more in depth diagnostics about what the actual curl request looks like?
Here's the code:
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
curl_setopt($ch, CURLOPT_HEADER, 1); // just getting header to see if we got an auth token
curl_setopt($ch, CURLOPT_FILE, $fh);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLINFO_HEADER_OUT, 1); // capture the header info
curl_setopt($ch, CURLOPT_VERBOSE, 1); // turn verbose on
// execute the curl request
$rh = fopen("request.txt", "w"); // open request file handle
$verbose = fopen('php://temp', 'rw+');
curl_setopt($ch, CURLOPT_STDERR, $verbose);
curl_exec($ch); // execute request
$sent_request = curl_getinfo($ch, CURLINFO_HEADER_OUT);
fwrite($rh, $sent_request); // save the request info
fclose($rh);
!rewind($verbose);
$verboseLog = stream_get_contents($verbose);
echo "Verbose information:\n<pre>", htmlspecialchars($verboseLog), "</pre>\n";
This all works as far as it goes, but returns a 401 every time-- the API admin assures me that the username / pass I have is correct.
I was wondering if I'm somehow getting the URL value wrong, or not sending the right username / pass, but this info isn't printed in the request data saved:
HEAD /export/auth HTTP/1.1
Authorization: Basic Y2FpcmRzdW5mYTpENWlAaVM4cw==
Host: webservices.mycompany.com
Accept: */*
You can see that the username/pass is not recorded (I assume for security). The endpoint URL I think is the host value plus the start of the HEAD value, so webservices.mycompany.com/export/auth?
The "Verbose Information" statement prints nothing. Not sure why on this either!
Thanks for help.
EDIT: added verbose mode from Php - Debugging Curl thanks to commenter immulatin
If you set CURLINFO_HEADER_OUT to true, outgoing headers are available in the array returned by curl_getinfo(), under request_header key:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://foo.com/bar");
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "someusername:secretpassword");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_exec($ch);
$info = curl_getinfo($ch);
print_r($info['request_header']);
This will print:
GET /bar HTTP/1.1
Authorization: Basic c29tZXVzZXJuYW1lOnNlY3JldHBhc3N3b3Jk
Host: foo.com
Accept: */*
Note the auth details are base64-encoded:
echo base64_decode('c29tZXVzZXJuYW1lOnNlY3JldHBhc3N3b3Jk');
// prints: someusername:secretpassword
Also note that username and password need to be percent-encoded to escape any URL reserved characters (/, ?, &, : and so on) they might contain:
curl_setopt($ch, CURLOPT_USERPWD, urlencode($username).':'.urlencode($password));
You can also use a proxy tool like Charles to capture the outgoing request headers, data, etc. by passing the proxy details through CURLOPT_PROXY to your curl_setopt_array method.
For example:
$proxy = '127.0.0.1:8888';
$opt = array (
CURLOPT_URL => "http://www.example.com",
CURLOPT_PROXY => $proxy,
CURLOPT_POST => true,
CURLOPT_VERBOSE => true,
);
$ch = curl_init();
curl_setopt_array($ch, $opt);
curl_exec($ch);
curl_close($ch);
curl_getinfo() must be added before closing the curl handler
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://example.com/bar");
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "someusername:secretpassword");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_exec($ch);
$info = curl_getinfo($ch);
print_r($info['request_header']);
curl_close($ch);
The request is printed in a request.txt with details
$ch = curl_init();
$f = fopen('request.txt', 'w');
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_VERBOSE => 1,
CURLOPT_STDERR => $f,
));
$response = curl_exec($ch);
fclose($f);
curl_close($ch);
You can also use curl_getinfo() function.

Posting a Photo to Fousquare API V2

I'm trying to post a photo to Foursquare API using the /photos/add method, and I'm having a little difficulites. I either get a 401 (missing file) or 502 (foursquare is down). Here is my code:
$ch = curl_init();
// file image name and it's located in the same folder
$image = "cupcakes.jpg";
// I've tried all of these and no luck
$s = array("file" => "#".$image, "photo" => "#".$image, "image" => "#".$image);
// I've also tried to send raw data:
//curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents($image));
$url = "https://api.foursquare.com/v2/photos/add?oauth_token=TOKENHERE&checknId=4fecf6abe4b0369bc7389903";
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $s);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// image/jpeg type
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-type: image/jpeg"));
$result = curl_exec($ch);
$http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// I get either 502 / 401 (Foursquare is down or File is missing)
echo $result;
Anyone have any idea what I'm doing wrong? The documentation for the endpoint is here: https://developer.foursquare.com/docs/photos/add -- in particular it implies that the photo data should be body of the POST request?
I've fixed the problem, turns out the param that you need to send to foursquare is "photo". All the other params must be included in the POST array as well.
Even though the content-type is requested as "image/jpeg", I've just put in "Except:" and it works fine. I'm not 100% sure why that goes through, but it does. Updated code below:
$s = array("photo" => "#".$image, "checkinId" => "4fecf6abe4b0369bc7389903");
$url = "https://api.foursquare.com/v2/photos/add?oauth_token=TOKENHERE&v=20120609";
.....
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Expect:"));
Everything else can stay the same. Happy posting!

Categories