3

I am using UploadedFile class in symfony2 to upload image files. I have allowed images with mime type image/jpg and image/png. When I upload a png file from my system to server its mime type is changed automatically. I know its changed because when I fire this command:

file --mime-type /home/mysuer/img.png

it gives me this:

home/myuser/img.png: image/png

but when I upload file and print UploadedFile object it gives following output:

Array
(
    [media] => Symfony\Component\HttpFoundation\File\UploadedFile Object
        (
            [test:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 
            [originalName:Symfony\Component\HttpFoundation\File\UploadedFile:private] => img.png
            [mimeType:Symfony\Component\HttpFoundation\File\UploadedFile:private] => application/octet-stream
            [size:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 1246
            [error:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 0
            [pathName:SplFileInfo:private] => /tmp/phpivgnne
            [fileName:SplFileInfo:private] => phpivgnne
        )

)

Can any one suggest what's wrong?

EDIT

Here is my Code:

public function postFileAction(Request $request)
{
    print_r($request->files->all());//Prints All files


    $image = $request->files->get('media');
    echo $image->getClientMimeType();exit; //Mime Type Information

    if (empty($image)) {
        throw new FileException('Invalid File, Please Select a Valid File.');
    }

    $uploader = $this->get('application.file_uploader');

    if (!$this->container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')) {
        //authenticated (NON anonymous users)
        throw new InvalidParameterException('Invalid User, Please use valid credentials');
    }

    return $uploader->upload($image, $this->get('security.context')->getToken()->getUser()->getId());
}

PHPUnit Test Code

public function testPostFile()
{
    $file    = tempnam(sys_get_temp_dir(), 'upl'); // create file
    imagepng(imagecreatetruecolor(10, 10), $file); // create and write image/png to it
    $image   = new UploadedFile($file, 'new_image.png', 'image/png', 10, UPLOAD_ERR_OK);
    $crawler = $this->client->request(
            'POST', '/api/v1/files.json', array('submit' => 'Submit Form'), array('media' => $image)
    );

    $response = $this->client->getResponse();

    $this->assertJsonResponse($response);
    $this->assertContains('filename', $response->getContent());

    print_r($response->getContent());exit;

    $fileToken = json_decode($response->getContent());
    $this->assertNotEmpty($fileToken->filename);

    unlink($file);
    unset($file, $image, $crawler, $response);

    return $fileToken->filename;
}

I am using curl from command prompt to test my REST web service file upload like this:

curl -X POST myapi.com/app_dev.php/api/v1/files.json --form "media=@/home/myuser/img.png"
Ashish Awasthi
  • 1,484
  • 1
  • 19
  • 34
  • maybe you should check the extension of the file instead of MIME type here. – techie_28 Nov 14 '14 at 09:06
  • What if someone upload an exe with .png extension? I don’t want to go with extensions I just want to go with mime-type. this is a strange behaviour, I have never faced such issues with file upload using php – Ashish Awasthi Nov 14 '14 at 09:10
  • It might happen because of request content-type header. The file might be sent as application/octet-stream, so the Symfony defines its mime-type properly, basing on header. – Alex Nov 14 '14 at 09:16
  • any suggestions how can I fix it if its header should I add header Content-Type: image/png while uploading image – Ashish Awasthi Nov 14 '14 at 09:21
  • can you show us your html file and your upload function ? Thx. – Perroin Thibault Nov 14 '14 at 09:28
  • Code added. As you can see right now nothing special done, just printed media, which gives me above given output with wrong mime type. I have separate service which checks for mime type and uploads file to Amazon S3, but I am getting error in the first step itself. – Ashish Awasthi Nov 14 '14 at 09:35
  • ok, can you show your html form ? Thx – Perroin Thibault Nov 14 '14 at 09:41
  • Very Sorry I forgot to mention its a REST based service so I am not using any html form instead using curl command line to post file and the same is done with android and getting the same error from both interfaces. Here is the command using cURL: curl -X POST myapi.com/app_dev.php/api/v1/files.json --form "media=@/home/myuser/img.png" Same code in my PHPUnit Tests is working fine. Will add the unit test also. – Ashish Awasthi Nov 14 '14 at 09:45
  • Ok, and do you post a "multipart" file ? see http://stackoverflow.com/questions/12667797/using-curl-to-upload-post-data-with-files – Perroin Thibault Nov 14 '14 at 10:18
  • -F or --form are same they do the same trick, and I am using --form – Ashish Awasthi Nov 14 '14 at 10:28
  • 1
    I've found this stack answer about mime types with android : http://stackoverflow.com/questions/8778151/android-image-file-sent-to-php-upload-image-file-is-application-octet-stream-typ. I can't help you anymore sorry... – Perroin Thibault Nov 14 '14 at 10:46
  • An EXE file with .PNG extension will never execute itself due to invalid extension. If your problem is Image specific,this might come helpful http://stackoverflow.com/questions/15408125/php-check-if-file-is-an-image – techie_28 Nov 16 '14 at 19:26
  • yeah, but its good to check and ignore such files. Thanks for the link but I have already searched and found the solution. Thanks for the help :D. This problem was to find the same solution in symfony2, rather then in core php, but the same solution work in both the places. – Ashish Awasthi Nov 17 '14 at 06:48

1 Answers1

7

Finally I got the solutions to my problem will post the answer for problem in both for core-php and for symfony2 also.

Core PHP(found on http://php.net/manual/en/features.file-upload.php):

// DO NOT TRUST $_FILES['upfile']['mime'] VALUE !!
// Check MIME Type by yourself.
$finfo = new finfo(FILEINFO_MIME_TYPE);
if (false === $ext = array_search(
    $finfo->file($_FILES['upfile']['tmp_name']),
    array(
        'jpg' => 'image/jpeg',
        'png' => 'image/png',
        'gif' => 'image/gif',
    ),
    true
)) {
    throw new RuntimeException('Invalid file format.');
}

So Never trust $_FILES['upfile']['mime'] always use fileinfo and this have given me the clue.

for Symfony2:

So I started looking into my code and found that I am using $file->getClientMimeType(), which is not good we have to use $file->getMimeType() which uses fileinfo to fetch mime type and will give the correct mime type.

In getMimeType() The mime type is guessed using a MimeTypeGuesser instance, which uses finfo(), mime_content_type() and the system binary "file" (in this order), depending on which of those are available.

Thanks Everyone for the Help :D

Ashish Awasthi
  • 1,484
  • 1
  • 19
  • 34