0

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;

}
André Figueira
  • 6,048
  • 14
  • 48
  • 62

3 Answers3

8

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

Luxian
  • 676
  • 7
  • 14
1

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.

André Figueira
  • 6,048
  • 14
  • 48
  • 62
0
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);
rohitarora
  • 1,380
  • 2
  • 13
  • 20
  • Not much for copy and pasting code, could you have a look at what I posted and try to help identify the issue, I need to fix the problem in my code. – André Figueira Feb 01 '13 at 12:55
  • you are not using curl properly that is why i have sent you the right curl code that works for every thing. `$this->extractRequestPostFields($postFields)` you dont need this in curl because if its an array it will automatically send data in the format you want to send it application/x-url-encoded and encrypt/multipart and you have to add a proper path where the file is store not the temp path – rohitarora Feb 01 '13 at 12:58
  • cURL is being used correctly, it's the part to which the file should be sent which isn't digging around the documentation I think I know what the issue is now. – André Figueira Feb 01 '13 at 13:01
  • you can use your code that fine but dont use $_File[]['tmp'] store it somewhere then paste the path in your $file = c:/uploadedfile/filename; – rohitarora Feb 01 '13 at 13:02
  • hmmm, I see what you mean, ok got an idea. – André Figueira Feb 01 '13 at 13:08