Теперь я пытаюсь настроить fineuploader-s3, чтобы показать изображение файла, успешно загруженного на сервер aws, как это было сделано на странице примера здесь: http://fineuploader.com/#s3-demo
Я (по-прежнему) использую код на https://github.com/Widen/fine-uploader-server/blob/master/php/s3/s3demo.php , и я добавил
uploadSuccess: { endpoint: "s3demo.php?success" }
к экземпляру fine-uploader в моем javascript-файле, так что временная ссылка должна быть сгенерирована функцией в файле s3demo.php.
Я понял, что мне пришлось установить AWS SDK, чтобы заставить это работать. Метод установки zip действительно не работал, поэтому я использую phar. Я изменил этот раздел файла s3demo.php на:
require 'aws.phar'; use Aws\S3\S3Client;
Я также раскупил эти две строки:
$serverPublicKey = $_SERVER['PARAM1']; $serverPrivateKey = $_SERVER['PARAM2'];
У меня возникают две проблемы, связанные с тем, чтобы это работало. Во-первых, что-то не так с моим успехом от AWS, из которого я думаю, что я должен получить ссылку на файл.
Файл загружается отлично, но я получаю сообщение об ошибке в консоли:
[FineUploader 3.8.0] Sending POST request for 0 s3.jquery.fineuploader-3.8.0.js:164 [FineUploader 3.8.0] Received the following response body to an AWS upload success request for id 0: <br /> <b>Fatal error</b>: Uncaught exception 'Guzzle\Http\Exception\CurlException' with message '[curl] 28: Connection timed out after 1001 milliseconds [url] http://169.254.169.254/latest/meta-data/iam/security-credentials/' in phar:///MYSITE/aws.phar/Guzzle/Http/Curl/CurlMulti.php:339 Stack trace: #0 phar:///MYSITE//aws.phar/Guzzle/Http/Curl/CurlMulti.php(280): Guzzle\Http\Curl\CurlMulti->isCurlException(Object(Guzzle\Http\Message\Request), Object(Guzzle\Http\Curl\CurlHandle), Array) #1 phar:///MYSITE//aws.phar/Guzzle/Http/Curl/CurlMulti.php(245): Guzzle\Http\Curl\CurlMulti->processResponse(Object(Guzzle\Http\Message\Request), Object(Guzzle\Http\Curl\CurlHandle), Array) #2 phar:///MYSITE//aws.phar/Guzzle/Http/Curl/CurlMulti.php(228): Guzzle\Http\Curl\CurlMulti->processMessages() #3 phar:///MYSITE//aws.phar/Guzzle/Http/Curl/CurlMulti.php(212): Guzzle\Http\Curl\CurlMulti->executeHandles() #4 phar:///MYSITE/z/aw in <b>phar:///home/nextq2/public_html/lenz/aws.phar/Aws/Common/InstanceMetadata/InstanceMetadataClient.php</b> on line <b>82</b><br /> s3.jquery.fineuploader-3.8.0.js:164 [FineUploader 3.8.0] Upload success was acknowledged by the server. s3.jquery.fineuploader-3.8.0.js:164
Означает ли это, что что-то не так с моей установкой AWS SDK или в моих настройках разрешений на Amazon? Для настроек CORS и IAM? Которые все еще выглядят следующим образом:
<CORSRule> <AllowedOrigin>MY WEBSITE</AllowedOrigin> <AllowedMethod>POST</AllowedMethod> <MaxAgeSeconds>3000</MaxAgeSeconds> <AllowedHeader>*</AllowedHeader> </CORSRule>
Моя групповая политика в IAM:
{ "Version":"2012-10-17", "Statement":[{ "Effect":"Allow", "Action":"s3:PutObject", "Resource":"arn:aws:s3:::MY_BUCKET/*” }] }
Вторая проблема, которая, я уверен, должна быть в состоянии выяснить, но не могу, – это получить доступ к массиву json, генерируемому s3demo.php, в моем javascript, чтобы я мог отображать загруженное изображение. Я думаю, что это не $ templink [0]. Мне было интересно, можно ли увидеть пример кода, который дает кнопку просмотра на http://fineuploader.com/#s3-demo его функции. Если мне стоит задать второй вопрос, я с удовольствием сделаю это.
Большое спасибо за ваше время.
EDIT, чтобы добавить мой полный код в соответствии с запросом:
PHP:
<?php /** * PHP Server-Side Example for Fine Uploader S3. * Maintained by Widen Enterprises. * * Note: This is the exact server-side code used by the S3 example * on fineuploader.com. * * This example: * - handles both CORS and non-CORS environments * - handles delete file requests for both DELETE and POST methods * - Performs basic inspections on the policy documents and REST headers before signing them * - Ensures again the file size does not exceed the max (after file is in S3) * - signs policy documents (simple uploads) and REST requests * (chunked/multipart uploads) * * Requirements: * - PHP 5.3 or newer * - Amazon PHP SDK (only if utilizing the AWS SDK for deleting files or otherwise examining them) * * If you need to install the AWS SDK, see http://docs.aws.amazon.com/aws-sdk-php-2/guide/latest/installation.html. */ // You can remove these two lines if you are not using Fine Uploader's // delete file feature require 'aws/aws-autoloader.php'; use Aws\S3\S3Client; // These assume you have the associated AWS keys stored in // the associated system environment variables $clientPrivateKey = 'I put my private key here; // These two keys are only needed if the delete file feature is enabled // or if you are, for example, confirming the file size in a successEndpoint // handler via S3's SDK, as we are doing in this example. $serverPublicKey = $_SERVER['PARAM1']; $serverPrivateKey = $_SERVER['PARAM2']; $expectedMaxSize = 15000000; $expectedBucket = “my bucket name here; $method = getRequestMethod(); // This first conditional will only ever evaluate to true in a // CORS environment if ($method == 'OPTIONS') { handlePreflight(); } // This second conditional will only ever evaluate to true if // the delete file feature is enabled else if ($method == "DELETE") { // handlePreflightedRequest(); // only needed in a CORS environment deleteObject(); } // This is all you really need if not using the delete file feature // and not working in a CORS environment else if ($method == 'POST') { handlePreflightedRequest(); // Assumes the successEndpoint has a parameter of "success" associated with it, // to allow the server to differentiate between a successEndpoint request // and other POST requests (all requests are sent to the same endpoint in this example). // This condition is not needed if you don't require a callback on upload success. if (isset($_REQUEST["success"])) { verifyFileInS3(); } else { signRequest(); } } // This will retrieve the "intended" request method. Normally, this is the // actual method of the request. Sometimes, though, the intended request method // must be hidden in the parameters of the request. For example, when attempting to // send a DELETE request in a cross-origin environment in IE9 or older, it is not // possible to send a DELETE request. So, we send a POST with the intended method, // DELETE, in a "_method" parameter. function getRequestMethod() { global $HTTP_RAW_POST_DATA; // This should only evaluate to true if the Content-Type is undefined // or unrecognized, such as when XDomainRequest has been used to // send the request. if(isset($HTTP_RAW_POST_DATA)) { parse_str($HTTP_RAW_POST_DATA, $_POST); } if ($_POST['_method'] != null) { return $_POST['_method']; } return $_SERVER['REQUEST_METHOD']; } // Only needed in cross-origin setups function handlePreflightedRequest() { // If you are relying on CORS, you will need to adjust the allowed domain here. //header('Access-Control-Allow-Origin: http://nextquestion.org'); } // Only needed in cross-origin setups function handlePreflight() { handlePreflightedRequest(); header('Access-Control-Allow-Methods: POST'); header('Access-Control-Allow-Headers: Content-Type'); } function getS3Client() { global $serverPublicKey, $serverPrivateKey; return S3Client::factory(array( 'key' => $serverPublicKey, 'secret' => $serverPrivateKey )); } // Only needed if the delete file feature is enabled function deleteObject() { getS3Client()->deleteObject(array( 'Bucket' => $_POST['bucket'], 'Key' => $_POST['key'] )); } function signRequest() { header('Content-Type: application/json'); $responseBody = file_get_contents('php://input'); $contentAsObject = json_decode($responseBody, true); $jsonContent = json_encode($contentAsObject); $headersStr = $contentAsObject["headers"]; if ($headersStr) { signRestRequest($headersStr); } else { signPolicy($jsonContent); } } function signRestRequest($headersStr) { if (isValidRestRequest($headersStr)) { $response = array('signature' => sign($headersStr)); echo json_encode($response); } else { echo json_encode(array("invalid" => true)); } } function isValidRestRequest($headersStr) { global $expectedBucket; $pattern = "/\/$expectedBucket\/.+$/"; preg_match($pattern, $headersStr, $matches); return count($matches) > 0; } function signPolicy($policyStr) { $policyObj = json_decode($policyStr, true); if (isPolicyValid($policyObj)) { $encodedPolicy = base64_encode($policyStr); $response = array('policy' => $encodedPolicy, 'signature' => sign($encodedPolicy)); echo json_encode($response); } else { echo json_encode(array("invalid" => true)); } } function isPolicyValid($policy) { global $expectedMaxSize, $expectedBucket; $conditions = $policy["conditions"]; $bucket = null; $parsedMaxSize = null; for ($i = 0; $i < count($conditions); ++$i) { $condition = $conditions[$i]; if (isset($condition["bucket"])) { $bucket = $condition["bucket"]; } else if (isset($condition[0]) && $condition[0] == "content-length-range") { $parsedMaxSize = $condition[2]; } } return $bucket == $expectedBucket && $parsedMaxSize == (string)$expectedMaxSize; } function sign($stringToSign) { global $clientPrivateKey; return base64_encode(hash_hmac( 'sha1', $stringToSign, $clientPrivateKey, true )); } // This is not needed if you don't require a callback on upload success. function verifyFileInS3() { global $expectedMaxSize; $bucket = $_POST["bucket"]; $key = $_POST["key"]; // If utilizing CORS, we return a 200 response with the error message in the body // to ensure Fine Uploader can parse the error message in IE9 and IE8, // since XDomainRequest is used on those browsers for CORS requests. XDomainRequest // does not allow access to the response body for non-success responses. if (getObjectSize($bucket, $key) > $expectedMaxSize) { // You can safely uncomment this next line if you are not depending on CORS //header("HTTP/1.0 500 Internal Server Error"); deleteObject(); echo json_encode(array("error" => "File is too big!")); } else { echo json_encode(array("tempLink" => getTempLink($bucket, $key))); } } function testfunction(){ alert('whatever'); } // Provide a time-bombed public link to the file. function getTempLink($bucket, $key) { $client = getS3Client(); $url = "{$bucket}/{$key}"; $request = $client->get($url); return $client->createPresignedUrl($request, '+15 minutes'); } function getObjectSize($bucket, $key) { $objInfo = getS3Client()->headObject(array( 'Bucket' => $bucket, 'Key' => $key )); return $objInfo['ContentLength']; } ?>
Мой html. Я использовал другой пример, который Марк имел в StackOverflow для этого теста, потому что в конце концов я хочу отправить некоторые другие данные одновременно:
<!DOCTYPE html> <html> <head> <title>test of fine uploader</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="fineuploader-3.8.0.css" rel="stylesheet"> <style> .button { display: block; height: 30px; width: 100px; border: 1px solid #000; } </style> <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script> <script src="s3.jquery.fineuploader-3.8.0.js"></script> <script type="text/javascript" src="lenz_javascript4.js"></script> </head> <body> <!-- Generated Image Thumbnail --> <a href="#" id="thumbnail">view image</a> <form action="fineuploadertest.php" method="post" id="uploader"> <input type="text" name="textbox" value="Test data"> <div id="manual-fine-uploader"></div> <div id="triggerUpload" class="button" style="margin-top: 10px;">click here </div> </form> </body> </html>
Мой javascript:
$(document).ready(function() { $("#triggerUpload").click(function () { $("#manual-fine-uploader").fineUploaderS3('uploadStoredFiles'); }); function submitForm () { if ($(this).fineUploader('getInProgress') == 0) { var failedUploads = $(this).fineUploaderS3('getUploads', { status: qq.status.UPLOAD_FAILED }); if (failedUploads.length == 0) { // do any other form processing here $("#uploader").submit(); } } }; $("#manual-fine-uploader").fineUploaderS3({ autoUpload: false, debug: true, request: { endpoint: "http://my bucket name.s3.amazonaws.com", accessKey: “I put my access key here” }, validation: { allowedExtensions: ['jpeg', 'jpg', 'gif', 'png'], sizeLimit: 15000000, itemLimit: 3 }, signature: { endpoint: "s3demo.php" }, camera: { ios: true }, iframeSupport: { localBlankPagePath: "/success.html" }, uploadSuccess: { endpoint: "s3demo.php?success" } }); });
Похоже, вы просто хотите отразить поведение демонстрации S3 на FineUploader.com. Итак, у части, с которой вы, по-видимому, возникают проблемы, является часть демонстрации, которая позволяет вам просматривать / загружать загруженный файл. Я предполагаю, что вы не устанавливаете переменные окружения PARAM1
и PARAM2
. Вы действительно должны посмотреть, как супер-глобальный $_SERVER
работает в документации PHP. Этот код, как он есть, ожидает, что у вас будет переменная системной среды с именем PARAM1
которая содержит общедоступный AWS-ключ, связанный с пользователем IAM, который вы должны создать для своего сервера (а не вашего клиента). PARAM2
системной среды PARAM2
должна быть установлена на секретный ключ для этого же пользователя. Вы можете либо установить эти переменные среды, либо установить связанные глобальные переменные $serverPublicKey
и $serverPrivateKey
PHP на общедоступные и секретные ключи пользователя IAM на стороне сервера, соответственно.
Обратите внимание, что неправильный выбор имени для переменных системной среды, связанных с общедоступным и секретным ключом AWS сервера ( PARAM1
и PARAM2
), связан с тем, что сервер для демонстрации Fineploader.com S3 работает на экземпляре AWS EC2, созданном Amazon's Упругий бобслей . Эластичный Beanstalk не предоставляет (по крайней мере, это явно не дает) способ назвать переменные системной среды через UI-интерфейс для использования PHP-приложений. Он называет их PARAM1
, PARAM2
и т. Д.
$serverPublicKey
и $serverPrivateKey
НЕ должны быть теми же ключами, которые связаны с пользователем IAM, созданным для задач на стороне клиента. Вы должны создать другого пользователя IAM с разрешениями, подходящими для задач на стороне сервера. Например, если вы хотите поддерживать функцию файла удаления, вы хотели бы иметь пользователя IAM с разрешением «S3: DeleteObject». Этот пользователь должен быть ограничен задачами на стороне сервера только по соображениям безопасности.
В вашем случае ваш пользователь IAM на стороне сервера должен иметь разрешение «S3: GetObject» на вашем ковше. Это разрешение требуется для получения объектов из вашего ведра. Самый безопасный подход заключается в предоставлении этого разрешения только для пользователя IAM на стороне сервера. Вероятно, вы спрашиваете: «Если мой клиентский пользователь не может читать объект из моего ведра, как разрешить загрузку файла на стороне клиента?» Ну, один из вариантов заключается в том, чтобы установить параметр acl
в Fine Uploader на «public-read», а затем сконструировать клиентскую часть URL, используя это соглашение: « http://mybucket.s3.amazonaws.com/objectkey ». Это НЕ способ, которым работает демонстрация S3 на сайте fineuploader.com. Читайте подробнее …
Я не хотел предоставлять пользователям неограниченный доступ к файлам, которые они загружали в ведомый файл Fine3, поэтому я оставил acl
«private» (значение по умолчанию), я дал только пользователю IAM на стороне сервера «S3: GetObject» в ящик Fine Uploader S3, и у меня есть сервер, который возвращает «связанный с бомбой» подписанный URL-адрес связанного объекта в ведре. URL-адрес, возвращаемый сервером, содержит параметр срока действия, который позволяет использовать его только 15 минут. Любые попытки изменить этот параметр истечения в строке запроса аннулируют подпись, и запрос будет терпеть неудачу. Функция getTempLink
в примере PHP будет генерировать подписанный по времени URL-адрес, который возвращается в ответ на uploadSucess.endpoint
POST для uploadSucess.endpoint
. Вы можете получить доступ к этому значению, предоставив complete
обработчик событий . Параметр объекта responseJSON
переданный в ваш обратный вызов, будет содержать свойство tempLink
которое будет содержать подписанный URL. Затем вы можете создать привязку с атрибутом src
установленным для значения этого свойства.