I use dropzone with CI, i don't know how to display error message and custom message when upload false, this is my script
Dropzone.autoDiscover = false;
try {
var myDropzone = new Dropzone("#adminform" , {
paramName: "filename", // The name that will be used to transfer the file
maxFilesize: 0.5, // MB
url: window.location.href,
addRemoveLinks : true,
dictDefaultMessage :
'<span class="bigger-150 bolder"><i class="ace-icon fa fa-caret-right red"></i> Drop files</span> to upload \
<span class="smaller-80 grey">(or click)</span> <br /> \
<i class="upload-icon ace-icon fa fa-cloud-upload blue fa-3x"></i>',
dictResponseError: 'Error while uploading file!',
//change the previewTemplate to use Bootstrap progress bars
previewTemplate: "<div class=\"dz-preview dz-file-preview\">\n <div class=\"dz-details\">\n <div class=\"dz-filename\"><span data-dz-name></span></div>\n <div class=\"dz-size\" data-dz-size></div>\n <img data-dz-thumbnail />\n </div>\n <div class=\"progress progress-small progress-striped active\"><div class=\"progress-bar progress-bar-success\" data-dz-uploadprogress></div></div>\n <div class=\"dz-success-mark\"><span></span></div>\n <div class=\"dz-error-mark\"><span></span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
});
}
catch(e) {
alert('Dropzone does not support older browsers!');
}
And PHP return 400:
$this->output->set_header("HTTP/1.0 400 Bad Request");
But when i hover image it's display [object Object] but message is:
dictResponseError: 'Error while uploading file!'
For anyone in need:
You can return a response message from the server using echo. Then in the js code add an error event handler
PHP
header("HTTP/1.0 400 Bad Request");
echo "Ups error message";
JS
this.on('error', function(file, response) {
$(file.previewElement).find('.dz-error-message').text(response);
});
For me this code finally worked, used as a dropzone option:
error: function(file, message) {
$(file.previewElement).addClass("dz-error").find('.dz-error-message').text(message.Message);
}
I used message.Message since the ASP.net WebAPI returns a JSON object, but not with the required "error" key.
You can simply echo back the message from server via PHP file
if($file_uploaded == true)
{
//perform operations on valid upload
} else {
//upload failed, echo back negative response to dropzone.js
$this->output->set_header("HTTP/1.0 400 Bad Request");
echo "Error uploading file";
}
While your HTML file can look like:
<script type="text/javascript">
Dropzone.options.myAwesomeDropzone = {
paramName: "icon_image", // The name that will be used to transfer the file
maxFilesize: 2, // MB
init: function() {
this.on("error", function(file, response) {
// do stuff here.
alert(response);
});
}
};
</script>
Hope it helps :)
Related
I searched on google and nothing...
i have a form in my view on vueJS :
<form #submit.prevent="avatar()" method="POST" enctype="multipart/form-data">
<input type="file" name="profilePicture" id="profilepicture" >
<button type="submit">Valider mon avatar?</button>
</form>
The user send an image.
My question is,
i want to send the image (sending by user with the form) in a function, and this function send the image to Http Request in headers ...
the api request begin with :
app.post('/myupload/:iduser', async (req, res) => {
try{
var { iduser } = req.params ;
const { image } = req.file ;
[...]
my function in my view on vuejs is actually :
async function avatar() {
console.log(document.getElementById("profilepicture").value);
// for having the image sending src
let response = await fetch(`http://localhost:196/myupload/${MyTokenStore.myid}`, {
method: "POST",
headers: {
"Content-Type": "multipart/form-data",
},
body: JSON.stringify(document.getElementById("profilepicture").value)
})
.then((response) => response.json())
.catch((error) => {
console.log("Failed", error)
});
if(response.error){
alert(response.message);
return
}
}
But the only parameter i make in request is the string of the src image, and the error servor is :
TypeError: Cannot destructure property 'image' of 'req.files' as it is undefined.
Please, i need help, the request run when I go directly to the url of the request (but the browser directly displays the server response):
<form :action="`http://localhost:196/myupload/${MyTokenStore.myid}`"
method="POST" enctype="multipart/form-data">
<input type="file" name="image"/>
<button type="submit">Valider mon avatar</button>
</form>
but I fail to put it in a function...
thank you.
To send an image from Vue doing a request you have to use a FormData object. For example:
/**
* #description - register user
*/
const register = async () => {
try {
const fd = new FormData();
Object.keys(user.value).forEach((key) => {
fd.append(key, user.value[key]);
});
const res = await axios.post('/register', fd, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
toast.success(res.data);
} catch (err) {
console.log(err);
toast.error(err.response.data);
}
};
In the previous code, in register I'm using a FormData to send the user object to the backend. Previously, you should set it. I made it like the following example:
const setProfileImage = (e) => {
image_preview.value = URL.createObjectURL(e.target.files[0]);
document.getElementById('image_preview').style.height = '150px';
document.getElementById('image_preview').style.width = '150px';
user.value.profile_image = e.target.files[0]; // this is important for you.
user.value.image = e.target.files[0].name;
};
setProfileImage is receiving an event from an Input file. If you see the comment I write in the code, user.value.profile_image = e.target.files[0] is the entire file. The rest is to display the image and send the name to store into the database.
<div class="mb-3">
<label
for="profile_image"
class="bg-primary text-white rounded-3 text-center w-100 p-2 profile_image"
>
Seleccione su foto de perfil <i class="ps-1 bi bi-card-image"></i>
</label>
<input
type="file"
class="form-control d-none"
id="profile_image"
placeholder="Adjunte su foto de perfil"
#change="setProfileImage"
/>
</div>
This is the Input file what I was talking. The event is an #change to catch correctly the file.
Hope it works for you.
<input type="file" name="default_image" id="imgInp" value="{{$property->default_image}}">
<div class="dropzone_upload">
<div class="dz-message" data-dz-message>
<span>
<img src='/assets/home/img/cloud_upload.png'/><br/>DRAG AND DROP IMAGES HERE <br/> <span class='or'>or</span> <br/> <a href='javascript:void(0)' class='upload_images'>UPLOAD IMAGES</a>
</span>
</div>
</div>
Now i have a problem when i upload default image and images in dropzone it mix those two so everything puts in default_image[].
Any suggestion how can i fix that?
When i do like this it say that image must be a type of jpeg,bmp,png:
$this->validate($request,[
'default_image' => 'mimes:jpeg,bmp,png|max:2000'
]);
This is my config for dropzone:
Dropzone.options.myDropzone = { // The camelized version of the ID of the form element
// The configuration we've talked about above
addRemoveLinks: true,
previewsContainer: '.dropzone-previews',
autoProcessQueue: false,
uploadMultiple: true,
parallelUploads: 10,
maxFiles: 10,
autoDiscover:false,
paramName:'gallery_images',
// The setting up of the dropzone
init: function() {
var myDropzone = this;
// First change the button to actually tell Dropzone to process the queue.
this.element.querySelector("button[type=submit]").addEventListener("click", function(e) {
// Make sure that the form isn't actually being sent.
if (myDropzone.getQueuedFiles().length > 0) {
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
}
});
// Listen to the sendingmultiple event. In this case, it's the sendingmultiple event instead
// of the sending event because uploadMultiple is set to true.
this.on("sendingmultiple", function() {
console.log('sendingmultiple');
// Gets triggered when the form is actually being sent.
// Hide the success button or the complete form.
});
this.on("successmultiple", function(files, response) {
console.log('successmultiple error',response);
// Gets triggered when the files have successfully been sent.
// Redirect user or notify of success.
$("html, body").animate({ scrollTop: 0 }, "slow");
$("#resultMsg").css('display', 'block').text(response.successMsg);
});
this.on("errormultiple", function(files, response) {
console.log('response error',response);
// Gets triggered when there was an error sending the files.
// Maybe show form again, and notify user of error
});
}
};
You need to use the rule like this:
$this->validate($request,[
'default_image.*' => 'mimes:jpeg,bmp,png|max:2000'
]);
For more details: https://laravel.com/docs/5.4/validation#validating-arrays
I have a page with a form that posts edits to a local endpoint via AJAX ($.post). I want to display a message to the user whether it went good or bad. But I can't get it to work. Here's what I have so far:
jade template (excerpt)
if message
.alert.alert-danger= message
// Tab panes
.tab-content
#admin-tab-profile.tab-pane.active(role='tabpanel')
h3 Profil
form
include partials/admin/profile
main.js (excerpt)
app.post('/admin', function(req, res) {
var data = req.body;
// find profile
profile.findById(data._id, function(err, profile) {
// update
profile.summary.da = data.da;
profile.summary.en = data.en;
// save
profile.save(function(err) {
if (err) {
req.flash('loginMessage', 'Oops! Something went wrong.');
res.status(500).send( { message: req.flash('loginMessage') } );
}
console.log("profile sucessfully updated");
req.flash('loginMessage', 'Yes! Everythings good!');
res.status(200).send( { message: req.flash('loginMessage') } );
});
});
});
app.js (excerpt)
app.use(flash()); // use connect-flash for flash messages stored in session
So what am I doing wrong? Why is not shown status messages when posting data?
Well if your using ajax you don't have to use express flash messages, you can simply use ajax.success method:
$.ajax({
method:'post',
url: '/user/singup',
data: data,
success: function(msg) {
console.log('Success!!');
console.log(msg); // loginMessage from your code
},
error: function() {
console.log('Error!!');
}
})
And send the status code from your post method in express:
res.status(200).send({ message: 'loginMessage' });
I managed to do that. I made it same as here:
https://www.npmjs.com/package/express-messages
<body>
<%- messages('my_message_template', locals) %>
<div id="messages">
<% Object.keys(messages).forEach(function (type) { %>
<% messages[type].forEach(function (message) { %>
<div class="alert alert-<%= type%>">
<%= message %>
</div>
<% }) %>
<% }) %>
</div>
And in $.ajax({ success:... I put this line:
$('#messages').load(location.href + " #messages");
So if ajax action was successful, it refreshed the div that id = messages.
In express I have this line:
res.status(200).json({ messages: req.flash('success','Yes! Everythings good')});
In above link, it states <%= type %> (ejs) if message is success or error (ie) and for that the styling is ie:
<style>
.alert-success{
color: #3c763d;
background-color: #dff0d8;
border-color: #d6e9c6;
}
.alert-error{
color: #a94442;
background-color: #f2dede;
border-color: #ebccd1;
}
</style>
This colors the background to green if message is 'success' or red if it's 'error'
I have been kicking around trying to implement the S3 uploader into my application and getting closer but no cigar. Here is my setup in a nutshell:
Running: 5.2.0 S3 with jQuery
Server: PHP 5.6.6 on ArchLinux
Max file size 25MB (defined in both s3.php and s3demo-cors.php)
Debug enabled: which just pops the Javascript alert with the XHR error code 0 message (can't seem to gain visibility into whats going on behind the scenes with debug or in the apache logs)
I specifically want to only use HTTPS for my bucket endpoint for security sake.
Testing with Google Chrome Version 42.0.2311.90 m and IE 11.0.9600
With Chrome it just fails, with IE it fails BUT it at least shows the progress meter for uploading the file, it hits 65% then fails.
I have followed the blog post here: http://blog.fineuploader.com/2013/08/16/fine-uploader-s3-upload-directly-to-amazon-s3-from-your-browser/ multiple times (hoping I am not missing something).
QUESTION: One thing I am curious about is the JSON policy and signing. I am not really seeing the code in the s3demo-cors.php example that creates the json formatted details perhaps I am missing that element?
I know my IAM permissions are valid because other PHP tests allow various PutObject and list commands successfully.
I have verified my CORS config is setup as follows for testing:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<ExposeHeader>ETag</ExposeHeader>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
I have a few files I am using for this:
s3.php = my test page with the fineuploader instance
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- jQuery
====================================================================== -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<!-- Fine Uploader Gallery CSS file
====================================================================== -->
<link href="fine-uploader-gallery.css" rel="stylesheet">
<!-- Fine Uploader S3 jQuery JS file
====================================================================== -->
<script src="s3.jquery.fine-uploader.js"></script>
<!-- Fine Uploader Customized Gallery template
====================================================================== -->
<script type="text/template" id="qq-template-s3">
<div class="qq-uploader-selector qq-uploader qq-gallery" qq-drop-area-text="Drop files here">
<div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container">
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div>
</div>
<div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
<span class="qq-upload-drop-area-text-selector"></span>
</div>
<div class="qq-upload-button-selector qq-upload-button">
<div>Upload a file</div>
</div>
<span class="qq-drop-processing-selector qq-drop-processing">
<span>Processing dropped files...</span>
<span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
</span>
<ul class="qq-upload-list-selector qq-upload-list" role="region" aria-live="polite" aria-relevant="additions removals">
<li>
<span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span>
<div class="qq-progress-bar-container-selector qq-progress-bar-container">
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-progress-bar-selector qq-progress-bar"></div>
</div>
<span class="qq-upload-spinner-selector qq-upload-spinner"></span>
<div class="qq-thumbnail-wrapper">
<a class="preview-link" target="_blank">
<img class="qq-thumbnail-selector" qq-max-size="120" qq-server-scale>
</a>
</div>
<button class="qq-upload-cancel-selector qq-upload-cancel">X</button>
<button class="qq-upload-retry-selector qq-upload-retry">
<span class="qq-btn qq-retry-icon" aria-label="Retry"></span>
Retry
</button>
<div class="qq-file-info">
<div class="qq-file-name">
<span class="qq-upload-file-selector qq-upload-file"></span>
<span class="qq-edit-filename-icon-selector qq-edit-filename-icon" aria-label="Edit filename"></span>
</div>
<input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
<span class="qq-upload-size-selector qq-upload-size"></span>
<button class="qq-btn qq-upload-delete-selector qq-upload-delete">
<span class="qq-btn qq-delete-icon" aria-label="Delete"></span>
</button>
<button class="qq-btn qq-upload-pause-selector qq-upload-pause">
<span class="qq-btn qq-pause-icon" aria-label="Pause"></span>
</button>
<button class="qq-btn qq-upload-continue-selector qq-upload-continue">
<span class="qq-btn qq-continue-icon" aria-label="Continue"></span>
</button>
</div>
</li>
</ul>
<dialog class="qq-alert-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<div class="qq-dialog-buttons">
<button class="qq-cancel-button-selector">Close</button>
</div>
</dialog>
<dialog class="qq-confirm-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<div class="qq-dialog-buttons">
<button class="qq-cancel-button-selector">No</button>
<button class="qq-ok-button-selector">Yes</button>
</div>
</dialog>
<dialog class="qq-prompt-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<input type="text">
<div class="qq-dialog-buttons">
<button class="qq-cancel-button-selector">Cancel</button>
<button class="qq-ok-button-selector">Ok</button>
</div>
</dialog>
</div>
</script>
<style>
#fine-uploader-s3 .preview-link {
display: block;
height: 100%;
width: 100%;
}
</style>
<title>Fine Uploader S3 Demo</title>
</head>
<body>
<!-- Fine Uploader DOM Element
====================================================================== -->
<div id="fine-uploader-s3"></div>
<!-- Your code to create an instance of Fine Uploader and bind to the DOM/template
====================================================================== -->
<script>
$('#fine-uploader-s3').fineUploaderS3({
debug: true,
template: 'qq-template-s3',
request: {
endpoint: "https://s3.amazonaws.com/<HIDDEN>",
accessKey: "<HIDDEN>"
},
signature: {
endpoint: "s3demo-cors.php"
},
uploadSuccess: {
endpoint: "s3demo-cors.php?success",
params: {
isBrowserPreviewCapable: qq.supportedFeatures.imagePreviews
}
},
iframeSupport: {
localBlankPagePath: "success.php"
},
cors: {
expected: true
},
chunking: {
enabled: true
},
resume: {
enabled: true
},
retry: {
enableAuto: true // defaults to false
},
deleteFile: {
enabled: true,
method: "POST",
endpoint: "s3demo-cors.php"
},
validation: {
itemLimit: 100,
sizeLimit: 25000000
},
thumbnails: {
placeholders: {
notAvailablePath: "not_available-generic.png",
waitingPath: "waiting-generic.png"
}
},
callbacks: {
onComplete: function(id, name, response) {
var previewLink = qq(this.getItemByFileId(id)).getByClass('preview-link')[0];
if (response.success) {
previewLink.setAttribute("href", response.tempLink)
}
},
onError: function(id, name, errorReason, xhrOrXdr) {
alert(qq.format("Error on file number {} - {}. Reason: {}", id, name, errorReason));
}
}
});
</script>
</body>
</html>
My PHP server side code is from your examples s3demo-cors.php
(sorry code formatting got a little garbled when pasting in here)
<?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)
* - returns a thumbnailUrl in the response for older browsers so thumbnails can be displayed next to the file
*
* 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-autoloader.php';
require 'vendor/autoload.php';
use Aws\S3\S3Client;
// These assume you have the associated AWS keys stored in
// the associated system environment variables
$clientPrivateKey = '<HIDDEN>';
// 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'];
// The following variables are used when validating the policy document
// sent by the uploader:
$expectedBucketName = "<HIDDEN>";
// $expectedMaxSize is the value you set the sizeLimit property of the
// validation option. We assume it is `null` here. If you are performing
// validation, then change this to match the integer value you specified
// otherwise your policy document will be invalid.
// http://docs.fineuploader.com/branch/develop/api/options.html#validation- option
$expectedMaxSize = 25000000;
$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") {
handleCorsRequest(); // 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') {
handleCorsRequest();
// 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(shouldIncludeThumbnail());
}
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 (isset($_POST['_method'])) {
return $_POST['_method'];
}
return $_SERVER['REQUEST_METHOD'];
}
// Only needed in cross-origin setups
function handleCorsRequest() {
// If you are relying on CORS, you will need to adjust the allowed domain here.
header('Access-Control-Allow-Origin: *');
}
// Only needed in cross-origin setups
function handlePreflight() {
handleCorsRequest();
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);
if (!empty($contentAsObject["headers"])) {
signRestRequest($contentAsObject["headers"]);
}
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 $expectedBucketName;
$pattern = "/\/$expectedBucketName\/.+$/";
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, $expectedBucketName;
$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 == $expectedBucketName && $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($includeThumbnail) {
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 (isset($expectedMaxSize) && 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!", "preventRetry" => true));
}
else {
$link = getTempLink($bucket, $key);
$response = array("tempLink" => $link);
if ($includeThumbnail) {
$response["thumbnailUrl"] = $link;
}
echo json_encode($response);
}
}
// 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'];
}
// Return true if it's likely that the associate file is natively
// viewable in a browser. For simplicity, just uses the file extension
// to make this determination, along with an array of extensions that one
// would expect all supported browsers are able to render natively.
function isFileViewableImage($filename) {
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$viewableExtensions = array("jpeg", "jpg", "gif", "png");
return in_array($ext, $viewableExtensions);
}
// Returns true if we should attempt to include a link
// to a thumbnail in the uploadSuccess response. In it's simplest form
// (which is our goal here - keep it simple) we only include a link to
// a viewable image and only if the browser is not capable of generating a client-side preview.
function shouldIncludeThumbnail() {
$filename = $_POST["name"];
$isPreviewCapable = $_POST["isBrowserPreviewCapable"] == "true";
$isFileViewableImage = isFileViewableImage($filename);
return !$isPreviewCapable && $isFileViewableImage;
}
?>
Based on your follow-up comment explaining the specific issue:
So digging around I see the following error: XMLHttpRequest cannot load s3.amazonaws.com/dev-pre-content. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '192.168.1.215'; is therefore not allowed access.
The problem is with your bucket's CORS configuration. You'll need to be sure you have appropriate CORS rules associated with the specific bucket you are uploading to.
It was exactly what you said, I believe that should implement the policy signature. When you send the file directly to the S3 server, you must first inform the política assignature, so your javascript will pass the credentials that will be on your php file, so that after you send the files you want.
Here is a working example of política signature
$AWSbucket = 'yout burcket';
$AWSkey = 'your key';
$AWSsecret = 'your secret';
$acl = 'public-read';
// Get the file extension
$file = $_POST['name'];
$extension = substr($_POST['name'], strrpos($_POST['name'], '.')+1);
// Prepare the filename
$fileName = 'c' . sha1(uniqid(mt_rand(), true));
$key = 'arquivos/'.$fileName . '.' . $extension;
// Set the expiration time of the policy
$policyExpiration = gmdate('Y-m-d\TH:i:s\Z', strtotime('+24 hour'));
// Set the policy
$policy = str_replace("\n", "", '
{"expiration": "' . $policyExpiration . '",
"conditions": [
{"acl": "' . $acl . '"},
{"bucket": "' . $AWSbucket . '"},
{"success_action_status": "201"},
["starts-with", "$key", "' . $key . '"],
]
}');
// 1 - Encode the policy using UTF-8.
// 2 - Encode those UTF-8 bytes using Base64.
// 3 - Sign the policy with your Secret Access Key using HMAC SHA-1.
// 4 - Encode the SHA-1 signature using Base64.
// Prepare the signature
$b64 = base64_encode(utf8_encode($policy));
$signature = base64_encode(hash_hmac('sha1', $b64, $AWSsecret, true));
// Return the post information
echo json_encode(array(
'key' => $key,
'acl' => $acl,
'MinPartSize' => 25 * 1024 * 1024,
'policy' => $b64,
'signature' => $signature,
'AWSAccessKeyId' => $AWSkey,
'success_action_status' => 201,
'bucket' => $AWSbucket
));
I need to upload multiple files as one request.
For example, i have two required files (.csv & .ctl) that I need to save.
Basically on the server side, I'm reading the .csv file and checking it against the .ctl file. If certain criteria doesn't match, I don't need to upload it. I'm not sure how or need to update the 'upload' method to read the filenames[]. Nor if I need to update this line "uploader.fineUploader('uploadStoredFiles');" to now accept the filenames[] after the user clicks "Upload now."
<script type="text/javascript">
$(document).ready(function () {
var filenames = [];
var uploader = $("#fine-uploader").fineUploader({
request: {
endpoint: '<%= ResolveUrl("~/Handler/UploadHandler.ashx")%>'
},
autoUpload: false,
text: {
uploadButton: '<span class="glyphicon glyphicon-plus"></span> Select Files'
},
validation: {
allowedExtensions: ['csv', 'ctl']
},
showMessage: function (message) {
// Using Bootstrap's classes
$('#fine-uploader').append('<div class="alert alert-danger">' + message + '</div>');
}
}).on('validate', function (event, fileData) {
return $.inArray(fileData.name, filenames) < 0;
}).on('submitted', function (event, fileId, fileName) {
filenames.push(fileName);
}).on('upload', function (event, fileId, fileName) {
var fileItemContainer = $(this).fineUploader('getItemByFileId', fileId);
$(this).fineUploader('setParams', { uploadType: 'VendorFileType', vendorId: '<%=vendorDropdownList1.CurrentVendorID %>' }, fileId);
}).on('complete', function (event, fileName, fileName, responseJSON) {
if (responseJSON.success) {
var div = document.getElementById('fine-uploader-status');
div.innerHTML = 'Upload process complete.';
}
else {
var div = document.getElementById('fine-uploader-status');
div.innerHTML = 'Upload denied.';
}
});
$('#uploadSelectedFiles').click(function () {
uploader.fineUploader('uploadStoredFiles');
});
});
</script>
//here's the aspx side.
<div id="fine-uploader">
</div>
<div id="fine-uploader-status">
</div>
<button id="uploadSelectedFiles" class="btn btn-primary">
<span class="glyphicon glyphicon-upload"></span>Upload now</button>
Fine Uploader does not support sending multiple files in a single request. This complicates the code unnecessarily and would break some existing features. Each file is sent in a separate request. You say you are performing some server-side checks to prevent uploads, but the files have already been uploaded by the time your server is able to perform these comparisons anyway. It's not clear from your question why you need to upload multiple files in a single request, or what benefit this gives you. If you clarify, perhaps I can provide alternate suggestions.