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
Related
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?
-----------------------------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.
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.
I'm generating emails in a PHP application which attach multiple files to an HTML email. Some of the files are Excel spreadsheets, some of the files are company logos which need to be embedded in the HTML so they load by default using Content-ID and cid identifiers to refer to the attached images.
As far as I can see, my syntax is correct, but the images don't ever load inline (they are attached successfully, however).
From: email#example.com
Reply-To: email#example.com
MIME-Version: 1.0
Content-type: multipart/mixed;boundary="d0f4ad49cc20d19bf96d4adf9322d567"
Message-Id: <20150421165500.0A5488021B#server>
Date: Tue, 21 Apr 2015 12:54:59 -0400 (EDT)
--d0f4ad49cc20d19bf96d4adf9322d567
Content-type: text/html; charset=utf-8
Content-transfer-encoding: 8bit
<html>
Html message goes here, followed by email.<br/>
<img src="cid:mylogo" />
</html>
--d0f4ad49cc20d19bf96d4adf9322d567
Content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; name=excelsheet.xlsx
Content-Description: excelsheet.xlsx
Content-Disposition: attachment;
filename="excelsheet.xlsx"; size=24712;
Content-transfer-encoding:base64
[base64 encoded string goes here.]
--b19e863e2cf66b40db1d138b7009010c
Content-Type: image/jpeg;
name="mylogo.jpg"
Content-transfer-encoding:base64
Content-ID: <mylogo>
Content-Disposition: inline;
filename="mylogo.jpg"; size=7579;
[base64 encoded string goes here.]
--b19e863e2cf66b40db1d138b7009010c--
Can anybody see an obvious reason why the image won't embed as expected?
EDIT
Note this behaviour isn't general to all email clients. So far only noted in Thunderbird.
I noticed two issues:
The MIME-boundary is inconsistent. For the first attachment it's d0f4ad49cc20d19bf96d4adf9322d567 and then b19e863e2cf66b40db1d138b7009010c is used. Thus, technically the second attachment is "part" of the first attachment.
If you replace all b19e863e2cf66b40db1d138b7009010c by d0f4ad49cc20d19bf96d4adf9322d567 Thunderbird correctly identifies the image attachment.
Use multipart/related instead of multipart/mixed. (see RFC2387)
A multipart/related is used to indicate that each message part is a component of an aggregate whole. It is for compound objects consisting of several inter-related components - proper display cannot be achieved by individually displaying the constituent parts. The message consists of a root part (by default, the first) which reference other parts inline, which may in turn reference other parts. Message parts are commonly referenced by the "Content-ID" part header. (see Wikipedia entry for MIME multipart/related)
I wanted to upload a file(any format) to an api. If I upload the file using multipart/form-data then the file gets uploaded.
I wanted to upload the file using application/json as the Content-type in the header.
Could you'll tell me if this method is possible/allowed?
Which are Content-type besides multipart/form-data which supports file upload?
Is there a single standard for content type which can be used for get, put, post etc.
Thanks in Advance.
Only multipart/form-data can trigger the population of the PHP $_FILES global, otherwise you're going to need to nest your attachment data in your API request if using something like JSON or XML (base64_encoding comes to mind)
You could also process a PUT request - http://www.php.net/manual/en/features.file-upload.put-method.php
RFC 4627:
The MIME media type for JSON text is application/json