André Figueira
André Figueira

Reputation: 6696

cURL not sending file to API CALL

I am building a mobile site that runs from an API and have an API CALL handler class which does all the calls which I run from a primary functions file.

The issue here is my files are not being sent through to the API and it's not recognising what is a file and is returning a file not present error.

NOTE: ISSUE SOLVED AND WORKING CODE BELOW

Code Below:

FORM

<form id="uploadPhoto" action="<?php uploadStreamPhoto(); ?>" method="post" enctype="multipart/form-data">
    <input type="file" name="streamPhotoUpload" id="streamPhotoUpload" />
    <input type="submit" name="streamPhotoUploadSubmit" id="streamPhotoUploadSubmit" value="Upload" />
</form>

UPLOAD FUNCTION

function uploadStreamPhoto()
{

    if(isset($_POST['streamPhotoUploadSubmit']))
    {

        $apiHandler = new APIHandler();
        $result = $apiHandler->uploadStreamPhoto($_FILES['streamPhotoUpload']['tmp_name']);
        $json = json_decode($result);
        var_dump($json);

        //header('Location: '.BASE_URL.'stream-upload-preview');

    }

}

HANDLER METHOD

public function uploadStreamPhoto($file)
{

    $result = $this->request(API_URL_ADD_PHOTO, array(
    'accessToken' => $this->accessToken,
    'file' => "@$file;filename=".time().".jpg",
    'photoName' => time(),
    'albumName' => 'Stream'
    )); 

    return $result;

}

CURL REQUEST METHOD

/**
* Creates a curl request with the information passed in post fields
*
* @access private
* @param string $url
* @param array $postFields
* @return string
**/
private function request($url, $postFields = array())
{

    $curl = curl_init();

    //Check the SSL Matches the host
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);

    if($this->debug == true)
    {

        //Prevent curl from verifying the certificate
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);

    }

    //Set the URL to call
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_HEADER, 0);

    //Set the results to be returned
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

    //Set the curl request as a post
    curl_setopt($curl, CURLOPT_POST, 1); 

    //Set the post fields
    curl_setopt($curl, CURLOPT_POSTFIELDS, $postFields); 

    $result = curl_exec($curl);

    if($result === false)
    {

        $result = 'Curl error: '.curl_error($curl);

    }

    curl_close($curl);

    return $result;

}

Upvotes: 0

Views: 3908

Answers (3)

Luxian
Luxian

Reputation: 676

My 2 cents for those ending up here by after the release of PHP 5.5. There are two things worth mentioning:

PHP 5.5 change

In PHP 5.5 a new function was introduced that changed the file upload procedure. rfc:curl-file-uploads describes it the best. So if you are using PHP 5.5 or newer, you should probably try to use curl_file_create() instead of adding @/full/file/path as the file field value.

Using legacy method in PHP 5.5 or newer

If you are using PHP 5.5 or newer, you might encounter issues when using old way of uploading files.

First of them is the fact that you have to use CURLOPT_SAFE_UPLOAD option and set it to FALSE.

Second, and the thing that made me spend hours debugging, is that you have to do this before setting CULROPT_POSTFIELDS. If you use curl_setopt_array() then CURLOPT_SAFE_UPLOAD should be added to that array before CURLOPT_POSTFIELDS. If you are using curl_setopt() then you just have to set CURLOPT_SAFE_UPLOAD before. Failing to do this will cause the file fields to be send as text containing @/full/file/path string instead of properly uploading files.

Example using legacy method but should work even with newer versions

<?php
$options = array(
  CURLOPT_URL => $url,
  CURLOPT_RETURNTRANSFER => TRUE,
  CURLOPT_SAFE_UPLOAD => FALSE,
  CURLOPT_POSTFIELDS => array(
    'text1' => 'test',
    'submit' => 'Send!',
    'file1' => '@' . realpath('images/a.jpg'),
    'file2' => '@' . realpath('images/b.jpg'),
  ),
);
$ch = curl_init();
// Needed for PHP > 5.5 to enable the old method of uploading file.
// Make sure to include this before CURLOPT_POSTFIELDS.
if (defined('CURLOPT_SAFE_UPLOAD')) {
  curl_setopt($ch, CURLOPT_SAFE_UPLOAD, FALSE);
}
curl_setopt_array($ch, $options);
$content = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);

full code here

PHP 5.5 or newer should be used like this

$options = array(
  CURLOPT_URL => $url,
  CURLOPT_RETURNTRANSFER => TRUE,
  CURLOPT_POSTFIELDS => array(
    'text1' => 'test',
    'submit' => 'Send!',
    'file1' => curl_file_create(realpath('images/a.jpg')),
    'file2' => curl_file_create(realpath('images/b.jpg')),
  ),
);

$ch = curl_init();
curl_setopt_array($ch, $options);
$content = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);

full code here

Upvotes: 8

Andr&#233; Figueira
Andr&#233; Figueira

Reputation: 6696

OK I have found out what the issue was, hopefully the solution will help a lot of people who don't want to change how their code is in lieu of someone elses.

cURL was not detecting that it was supposed to send this form as a multipart so it was sending the post as a default encoding meaning the other end wasn't receiving the $_FILES variable.

To solve this you need to give the postdata as an array, I was creating the string for the send, I have removed this and am giving the CURLOPT_POSTFIELDS an array.

Another important thing when uploading directly from a form using cURL is to include the information for your file along with the actual file.

My API Call handler now created the array as follows:

public function uploadStreamPhoto($file)
{

    $result = $this->request(API_URL_ADD_PHOTO, array(
    'accessToken' => $this->accessToken,
    'file' => "@$file;filename=".time().".jpg",
    'photoName' => time(),
    'albumName' => 'Stream'
    )); 

    return $result;

}

Take note that the $file variable is $_FILES['tmp_name'] You then also have to define the file name. I will be updating the question with the solution.

Upvotes: 1

rohitarora
rohitarora

Reputation: 1365

function curl_grab_page($url,$data,$secure="false",$ref_url="",$login = "false",$proxy = "null",$proxystatus = "false")

            {
                if($login == 'true') {
                    $fp = fopen("cookie.txt", "w");
                    fclose($fp);
                }
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_COOKIEJAR, "cookie.txt");
                curl_setopt($ch, CURLOPT_COOKIEFILE, "cookie.txt");

                curl_setopt($ch, CURLOPT_TIMEOUT, 60);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
                if ($proxystatus == 'true') {
                    curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, TRUE);
                    curl_setopt($ch, CURLOPT_PROXY, $proxy);
                }
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

                if($secure=='true')
                {
                    curl_setopt($ch, CURLOPT_SSLVERSION,3);
                }

                curl_setopt( $ch, CURLOPT_HTTPHEADER, array( 'Expect:' ) );


                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                curl_setopt($ch, CURLOPT_REFERER, $ref_url);
                curl_setopt($ch, CURLOPT_HEADER, TRUE);
                curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
                curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
                curl_setopt($ch, CURLOPT_POST, TRUE);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
                ob_start();

                return curl_exec ($ch); // execute the curl command

                curl_getinfo($ch);
                ob_end_clean();
                curl_close ($ch);
                unset($ch);
            }

use this curl function according to your need as i was using it to send data in post even files.

and

$data['FileName'] = '@'.$ProperPath;

// Proper Path = c:/images/a.jpg

curl_grab_page("url", $data);

Upvotes: 0

Related Questions