Skip to content

Commit 6f85b2e

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

File tree

1 file changed

+2
-251
lines changed

1 file changed

+2
-251
lines changed

php/s3/s3demo.php

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