Skip to content

Commit e143f19

Browse files
committed
moved S3 PHP code to a dedicated repo + packagist/composer
1 parent 96b27ef commit e143f19

File tree

1 file changed

+2
-279
lines changed

1 file changed

+2
-279
lines changed

php/s3/s3demo-cors.php

+2-279
Original file line numberDiff line numberDiff line change
@@ -1,279 +1,2 @@
1-
<?php
2-
/**
3-
* PHP Server-Side Example for Fine Uploader S3.
4-
* Maintained by Widen Enterprises.
5-
*
6-
* Note: This is the exact server-side code used by the S3 example
7-
* on fineuploader.com.
8-
*
9-
* This example:
10-
* - handles both CORS and non-CORS environments
11-
* - handles delete file requests for both DELETE and POST methods
12-
* - Performs basic inspections on the policy documents and REST headers before signing them
13-
* - Ensures again the file size does not exceed the max (after file is in S3)
14-
* - signs policy documents (simple uploads) and REST requests
15-
* (chunked/multipart uploads)
16-
* - returns a thumbnailUrl in the response for older browsers so thumbnails can be displayed next to the file
17-
*
18-
* Requirements:
19-
* - PHP 5.3 or newer
20-
* - Amazon PHP SDK (only if utilizing the AWS SDK for deleting files or otherwise examining them)
21-
*
22-
* If you need to install the AWS SDK, see http://docs.aws.amazon.com/aws-sdk-php-2/guide/latest/installation.html.
23-
*/
24-
25-
// You can remove these two lines if you are not using Fine Uploader's
26-
// delete file feature
27-
require 'aws-autoloader.php';
28-
use Aws\S3\S3Client;
29-
30-
// These assume you have the associated AWS keys stored in
31-
// the associated system environment variables
32-
$clientPrivateKey = $_SERVER['AWS_SECRET_KEY'];
33-
// These two keys are only needed if the delete file feature is enabled
34-
// or if you are, for example, confirming the file size in a successEndpoint
35-
// handler via S3's SDK, as we are doing in this example.
36-
$serverPublicKey = $_SERVER['PARAM1'];
37-
$serverPrivateKey = $_SERVER['PARAM2'];
38-
39-
// The following variables are used when validating the policy document
40-
// sent by the uploader:
41-
$expectedBucketName = "upload.fineuploader.com";
42-
// $expectedMaxSize is the value you set the sizeLimit property of the
43-
// validation option. We assume it is `null` here. If you are performing
44-
// validation, then change this to match the integer value you specified
45-
// otherwise your policy document will be invalid.
46-
// http://docs.fineuploader.com/branch/develop/api/options.html#validation-option
47-
$expectedMaxSize = 15000000;
48-
49-
$method = getRequestMethod();
50-
51-
// This first conditional will only ever evaluate to true in a
52-
// CORS environment
53-
if ($method == 'OPTIONS') {
54-
handlePreflight();
55-
}
56-
// This second conditional will only ever evaluate to true if
57-
// the delete file feature is enabled
58-
else if ($method == "DELETE") {
59-
handleCorsRequest(); // only needed in a CORS environment
60-
deleteObject();
61-
}
62-
// This is all you really need if not using the delete file feature
63-
// and not working in a CORS environment
64-
else if ($method == 'POST') {
65-
handleCorsRequest();
66-
67-
// Assumes the successEndpoint has a parameter of "success" associated with it,
68-
// to allow the server to differentiate between a successEndpoint request
69-
// and other POST requests (all requests are sent to the same endpoint in this example).
70-
// This condition is not needed if you don't require a callback on upload success.
71-
if (isset($_REQUEST["success"])) {
72-
verifyFileInS3(shouldIncludeThumbnail());
73-
}
74-
else {
75-
signRequest();
76-
}
77-
}
78-
79-
// This will retrieve the "intended" request method. Normally, this is the
80-
// actual method of the request. Sometimes, though, the intended request method
81-
// must be hidden in the parameters of the request. For example, when attempting to
82-
// send a DELETE request in a cross-origin environment in IE9 or older, it is not
83-
// possible to send a DELETE request. So, we send a POST with the intended method,
84-
// DELETE, in a "_method" parameter.
85-
function getRequestMethod() {
86-
global $HTTP_RAW_POST_DATA;
87-
88-
// This should only evaluate to true if the Content-Type is undefined
89-
// or unrecognized, such as when XDomainRequest has been used to
90-
// send the request.
91-
if(isset($HTTP_RAW_POST_DATA)) {
92-
parse_str($HTTP_RAW_POST_DATA, $_POST);
93-
}
94-
95-
if (isset($_POST['_method'])) {
96-
return $_POST['_method'];
97-
}
98-
99-
return $_SERVER['REQUEST_METHOD'];
100-
}
101-
102-
// Only needed in cross-origin setups
103-
function handleCorsRequest() {
104-
// If you are relying on CORS, you will need to adjust the allowed domain here.
105-
header('Access-Control-Allow-Origin: http://fineuploader.com');
106-
}
107-
108-
// Only needed in cross-origin setups
109-
function handlePreflight() {
110-
handleCorsRequest();
111-
header('Access-Control-Allow-Methods: POST');
112-
header('Access-Control-Allow-Headers: Content-Type');
113-
}
114-
115-
function getS3Client() {
116-
global $serverPublicKey, $serverPrivateKey;
117-
118-
return S3Client::factory(array(
119-
'key' => $serverPublicKey,
120-
'secret' => $serverPrivateKey
121-
));
122-
}
123-
124-
// Only needed if the delete file feature is enabled
125-
function deleteObject() {
126-
getS3Client()->deleteObject(array(
127-
'Bucket' => $_POST['bucket'],
128-
'Key' => $_POST['key']
129-
));
130-
}
131-
132-
function signRequest() {
133-
header('Content-Type: application/json');
134-
135-
$responseBody = file_get_contents('php://input');
136-
$contentAsObject = json_decode($responseBody, true);
137-
$jsonContent = json_encode($contentAsObject);
138-
139-
if (!empty($contentAsObject["headers"])) {
140-
signRestRequest($contentAsObject["headers"]);
141-
}
142-
else {
143-
signPolicy($jsonContent);
144-
}
145-
}
146-
147-
function signRestRequest($headersStr) {
148-
if (isValidRestRequest($headersStr)) {
149-
$response = array('signature' => sign($headersStr));
150-
echo json_encode($response);
151-
}
152-
else {
153-
echo json_encode(array("invalid" => true));
154-
}
155-
}
156-
157-
function isValidRestRequest($headersStr) {
158-
global $expectedBucketName;
159-
160-
$pattern = "/\/$expectedBucketName\/.+$/";
161-
preg_match($pattern, $headersStr, $matches);
162-
163-
return count($matches) > 0;
164-
}
165-
166-
function signPolicy($policyStr) {
167-
$policyObj = json_decode($policyStr, true);
168-
169-
if (isPolicyValid($policyObj)) {
170-
$encodedPolicy = base64_encode($policyStr);
171-
$response = array('policy' => $encodedPolicy, 'signature' => sign($encodedPolicy));
172-
echo json_encode($response);
173-
}
174-
else {
175-
echo json_encode(array("invalid" => true));
176-
}
177-
}
178-
179-
function isPolicyValid($policy) {
180-
global $expectedMaxSize, $expectedBucketName;
181-
182-
$conditions = $policy["conditions"];
183-
$bucket = null;
184-
$parsedMaxSize = null;
185-
186-
for ($i = 0; $i < count($conditions); ++$i) {
187-
$condition = $conditions[$i];
188-
189-
if (isset($condition["bucket"])) {
190-
$bucket = $condition["bucket"];
191-
}
192-
else if (isset($condition[0]) && $condition[0] == "content-length-range") {
193-
$parsedMaxSize = $condition[2];
194-
}
195-
}
196-
197-
return $bucket == $expectedBucketName && $parsedMaxSize == (string)$expectedMaxSize;
198-
}
199-
200-
function sign($stringToSign) {
201-
global $clientPrivateKey;
202-
203-
return base64_encode(hash_hmac(
204-
'sha1',
205-
$stringToSign,
206-
$clientPrivateKey,
207-
true
208-
));
209-
}
210-
211-
// This is not needed if you don't require a callback on upload success.
212-
function verifyFileInS3($includeThumbnail) {
213-
global $expectedMaxSize;
214-
215-
$bucket = $_POST["bucket"];
216-
$key = $_POST["key"];
217-
218-
// If utilizing CORS, we return a 200 response with the error message in the body
219-
// to ensure Fine Uploader can parse the error message in IE9 and IE8,
220-
// since XDomainRequest is used on those browsers for CORS requests. XDomainRequest
221-
// does not allow access to the response body for non-success responses.
222-
if (isset($expectedMaxSize) && getObjectSize($bucket, $key) > $expectedMaxSize) {
223-
// You can safely uncomment this next line if you are not depending on CORS
224-
header("HTTP/1.0 500 Internal Server Error");
225-
deleteObject();
226-
echo json_encode(array("error" => "File is too big!", "preventRetry" => true));
227-
}
228-
else {
229-
$link = getTempLink($bucket, $key);
230-
$response = array("tempLink" => $link);
231-
232-
if ($includeThumbnail) {
233-
$response["thumbnailUrl"] = $link;
234-
}
235-
236-
echo json_encode($response);
237-
}
238-
}
239-
240-
// Provide a time-bombed public link to the file.
241-
function getTempLink($bucket, $key) {
242-
$client = getS3Client();
243-
$url = "{$bucket}/{$key}";
244-
$request = $client->get($url);
245-
246-
return $client->createPresignedUrl($request, '+15 minutes');
247-
}
248-
249-
function getObjectSize($bucket, $key) {
250-
$objInfo = getS3Client()->headObject(array(
251-
'Bucket' => $bucket,
252-
'Key' => $key
253-
));
254-
return $objInfo['ContentLength'];
255-
}
256-
257-
// Return true if it's likely that the associate file is natively
258-
// viewable in a browser. For simplicity, just uses the file extension
259-
// to make this determination, along with an array of extensions that one
260-
// would expect all supported browsers are able to render natively.
261-
function isFileViewableImage($filename) {
262-
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
263-
$viewableExtensions = array("jpeg", "jpg", "gif", "png");
264-
265-
return in_array($ext, $viewableExtensions);
266-
}
267-
268-
// Returns true if we should attempt to include a link
269-
// to a thumbnail in the uploadSuccess response. In it's simplest form
270-
// (which is our goal here - keep it simple) we only include a link to
271-
// a viewable image and only if the browser is not capable of generating a client-side preview.
272-
function shouldIncludeThumbnail() {
273-
$filename = $_POST["name"];
274-
$isPreviewCapable = $_POST["isBrowserPreviewCapable"] == "true";
275-
$isFileViewableImage = isFileViewableImage($filename);
276-
277-
return !$isPreviewCapable && $isFileViewableImage;
278-
}
279-
?>
1+
The S3 PHP server example has moved to a new repository: https://github.com/FineUploader/php-s3-server.
2+
The server code is also available on packagist via composer under the name `fineuploader/php-s3-server`.

0 commit comments

Comments
 (0)