HTTP Post Upload Multiple Files from iOS to PHP - php

In my iOS app, I'm building an NSData to use as the body for an NSMutableURLRequest so that I can upload multiple files in one HTTP POST.
The contents of my post body look like this (with the file data removed and just replaced with the byte count):
multipart/form-data; charset=utf-8; boundary=0xKhTmLbOuNdArY
--0xKhTmLbOuNdArY
Content-Disposition: form-data; name="email"
myemailaddress#gmail.com
--0xKhTmLbOuNdArY
Content-Disposition: form-data; name="sqlite"; filename="backup.MyApp.v1.1.3-to-v1.1.3.1443578420.sqlite"
Content-Type: application/octet-stream
// ... data length: 880640
--0xKhTmLbOuNdArY--
Content-Disposition: form-data; name="sqliteshm"; filename="backup.MyApp.v1.1.3-to-v1.1.3.1443578420.sqlite-shm"
Content-Type: application/octet-stream
// ... data length: 32768
--0xKhTmLbOuNdArY--
Content-Disposition: form-data; name="sqlitewal"; filename="backup.MyApp.v1.1.3-to-v1.1.3.1443578420.sqlite-wal"
Content-Type: application/octet-stream
// ... data length: 3901672
--0xKhTmLbOuNdArY--
However, on the PHP side when I receive this post, I'm only seeing the first of the three files. If I put the one named "sqlite" first, then on the PHP side, I only see the "sqlite" file. If I put the one named "sqliteshm" first, then I only see the "sqliteshm" file in the $_FILES array.
array (
'sqliteshm' =>
array (
'name' => 'backup.MyApp.v1.1.3-to-v1.1.3.1443578420.sqlite-shm',
'type' => 'application/octet-stream',
'tmp_name' => '/private/var/tmp/phpk1wyWb',
'error' => 0,
'size' => 32768,
),
)
The file size matches up, regardless of which one I put first, but only the first file ever shows up on the PHP side.
Do I need to do something special in order to receive multiple files on the PHP side?
Or am I sending the multiple files incorrect from iOS?

In short, your request is not valid.
In more detail, notice the difference between --0xKhTmLbOuNdArY-- and --0xKhTmLbOuNdArY. The separator that uses two dashes at the end -- is a terminator. As a result, your request body isn't parsed beyond the first terminator, which happens to be the right after the first file. There should only be one terminator - at the very end of your request.
Generally, you shouldn't reinvent the wheel when it comes to composing multipart form data requests. Just use a proven and time tested library like AFNetworking.

Related

Multipart PUT in PHP (data and files)

I have been tasked with building the API for an existing mobile app. App is sending multipart data and files in the same PUT request. As an example, there is /api/employee/personal-info PUT endpoint (notice no ID in the URI) which is a multipart - JSON data and 2 images.
PHP does not have native support for PUT, it doesn't nicely put everything in $_FILES and $_POST so I have to decode the input manually.
I first have to do file_get_contents("php://input") which gives me the raw data. I have to use regex to extract the boundary string, then I need to split the input into blocks using that boundary (and regex again) and then decide whether the block is JSON or a file, by looking at Content-Disposition on each of the blocks. If it is a file, I have to regex out the filename and extension, and populate $_FILES array manually.
Json bloks have those headers (inside the body, just before the actual data)
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=model
and file blocks only have this:
Content-Disposition: form-data; name=file; filename=IMG_20180208_1.jpg; filename*=utf-8’’IMG_20180208_1.jpg
So the Content-Disposition of the whole input is multipart/form-data but then each of the blocks have their own headers, depending whether it is a file or JSON data.
Is this really the only way to do it in PHP?
Should the PUT endpoints NOT be multipart as a rule when it comes to PHP?
Am I missing something?

Laravel - Import File Using Octet-Stream

I was curious if anyone has ever imported a file where the post parameters in the developer bar is formatted like below with the content-type being application/octet-stream?
Below is just the first couple of lines of the parameters sent in the post data:
-----------------------------24464570528145
Content-Disposition: form-data; name="RemoteFile"; filename="594.pdf"
Content-Type: application/octet-stream
%PDF-1.5
1 0 obj
<<
/Creator ()
/CreationDate (2
I'm curious how I would upload the file through the model controller and I'm hoping someone else here might have run across this sort of issue.
Just use this one line of code
(new FileSystem)->put('/path/to/file.txt', $request->getContent());

How to check if Content-Type is manipulated before hitting the server

-----------------------------28762240629868
Content-Disposition: form-data; name="file"; filename="1.jpg"
Content-Type: text/html
ÿØÿà
....
If someone has deliberately changed the Content-Type from image/jpeg to text/html, how to detect it in server side ?
There could be a possibility that client can send files with manipulated content type. If you expect that the incoming attachment is going to be always image, then check for the height and width of image using below functions. If it return FALSE then its not an image.
imagesx($img);
http://php.net/manual/en/function.imagesx.php
imagesy($img);
http://php.net/manual/en/function.imagesy.php
Important:
For the safety purpose, DO NOT render/execute the attachment from url on webpage if you are not sure. Just always force download image. Send headers and force downloading it so that just in case user is able to upload say .EXE file then still he will not able to execute on browser.

POST parameters sent by form but not present in php script

I have a strange problem. I'm sending a very large form with hundreds of fields. Basically I have no doubt there is no errors with the form itself because in firefox's console I can see in my request that the POST array is present :
-----------------------------14624305211779581122436169227
Content-Disposition: form-data; name="BlocDocumentDocument[blocsTabulardocumentsTabularn0][n0][file]"
34495153-98c5-4200-8545-2bb71d279ecd
-----------------------------14624305211779581122436169227
Content-Disposition: form-data; name="BlocDocumentDocument[blocsTabulardocumentsTabularn0][n0][title]"
asdf
-----------------------------14624305211779581122436169227
Content-Disposition: form-data; name="BlocDocumentDocument[blocsTabulardocumentsTabularn0][n0][description]"
-----------------------------14624305211779581122436169227
Content-Disposition: form-data; name="BlocDocumentDocument[blocsTabulardocumentsTabularn0][n0][datetime]"
2014-09-19 00:00:00
-----------------------------14624305211779581122436169227
Content-Disposition: form-data; name="BlocDocumentDocument[blocsTabulardocumentsTabularn0][n0][rank]"
1
But if in php I print_r($_POST['BlocDocumentDocument']['blocsTabulardocumentsTabularn0']) in the first line of php I get the following :
Array
(
[n0] => Array
(
[file] => 34495153-98c5-4200-8545-2bb71d279ecd
)
)
There are fields missing. And this problem seems to only occur if the form has a large amount of fields (I have the same form but with less fields (they're generated by javascript) and it works). I already tried to increase php's post_max_size and it didn't work.
I have found the problem. It was php's max_input_vars setting. By default it's 1000 in 5.3.

HTTP PUT method in PHP: separating files from form data

When a file is uploaded via POST, the form data is separated out from the file(s) via the $_POST and $_FILES variables (respectively). On the other hand, when a file is uploaded via PUT, the response must be retrieved from a single source (php://input). Unfortunately, when a file is involved, php://input seems to contain multiple headers, which appear to be divided by a key of some kind (--6OJvloM5owOQsn2b3APr-Ad9dDLvRqBxm in this case).
--6OJvloM5owOQsn2b3APr-Ad9dDLvRqBxm
Content-Disposition: form-data; name="file"; filename="image.jpg"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
<<<BINARY DATA>>>
--6OJvloM5owOQsn2b3APr-Ad9dDLvRqBxm
Content-Disposition: form-data; name="description"
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
<<<FILE DESCRIPTION>>>
--6OJvloM5owOQsn2b3APr-Ad9dDLvRqBxm--
Short of iterating over the entire response and trying to pick out the different headers, is there a way to separate the files from the form data?
Note: I'm using a well-known 3rd-party application to make the API requests, so it's unlikely that the problem resides in the requests themselves.
It seems that you are trying to do to much in one PUT request. However, if you really need to handle the raw data, you should be able to parse it as a MIME string using a library such as this one: http://pear.php.net/package/Mail_mimeDecode

Categories