I am trying to implement large file upload with resumable.js and laravel-chunk-upload. Everything is working fine, that is I am able to upload large files properly but the problem is, if anything happens to network connection while uploading, then the uploads is not completing properly. one chunk gets error. the error is:
"message": "fopen(H:\\Codinoz\\Development\\File ECommerce\\digital-product-shopping\\storage\\app\\products/27-09-2021 CMF 20-21 before_166b6fa4934428d2952877c84bed0ef2.): Failed to open stream: Permission denied",
There is no permission problems, because the same function is working properly when there is no network problems.
current javascript code:
let browseFile = $('#browseFile');
let resumable = new Resumable({
target: '{{ route('files.upload.large') }}',
query:{_token:'{{ csrf_token() }}'} ,// CSRF token
//fileType: ['mp4'],
chunkSize: 10*1024*1024, // default is 1*1024*1024, this should be less than your maximum limit in php.ini
headers: {
'Accept' : 'application/json'
},
testChunks: false,
maxChunkRetries: 1000,
chunkRetryInterval: 2000,
throttleProgressCallbacks: 1,
});
resumable.assignBrowse(browseFile[0]);
resumable.on('fileAdded', function (file) { // trigger when file picked
showProgress();
resumable.upload() // to actually start uploading.
});
resumable.on('fileProgress', function (file) {
if(navigator.onLine === true){
// trigger when file progress update
updateProgress(Math.floor(file.progress() * 100));
}
else{
alert('no Internet');
}
});
resumable.on('fileSuccess', function (file, response) { // trigger when file upload complete
response = JSON.parse(response)
console.log('sss');
//$('#videoPreview').attr('src', response.path);
});
resumable.on('fileError', function (file, response) { // trigger when there is any error
console.log(response);
});
let progress = $('.progress');
function showProgress() {
progress.find('.progress-bar').css('width', '0%');
progress.find('.progress-bar').html('0%');
progress.find('.progress-bar').removeClass('bg-success');
progress.show();
}
function updateProgress(value) {
progress.find('.progress-bar').css('width', `${value}%`)
progress.find('.progress-bar').html(`${value}%`)
}
function hideProgress() {
progress.hide();
}
Laravel Server side code:
public function uploadLargeFiles(Request $request) {
$receiver = new FileReceiver('file', $request, HandlerFactory::classFromRequest($request));
if (!$receiver->isUploaded()) {
// file not uploaded
}
$fileReceived = $receiver->receive(); // receive file
if ($fileReceived->isFinished()) { // file uploading is complete / all chunks are uploaded
$file = $fileReceived->getFile(); // get file
$extension = $file->getClientOriginalExtension();
$fileName = str_replace('.'.$extension, '', $file->getClientOriginalName()); //file name without extenstion
$fileName .= '_' . md5(time()) . '.' . $extension; // a unique file name
$disk = Storage::disk(config('filesystems.default'));
$path = $disk->putFileAs('products', $file, $fileName);
// delete chunked file
unlink($file->getPathname());
return [
'path' => asset('storage/' . $path),
'filename' => $fileName
];
}
// otherwise return percentage information
$handler = $fileReceived->handler();
return [
'done' => $handler->getPercentageDone(),
'status' => true
];
}
I am a beginner in this, so not so good in finding solutions. Tried my best, but couldn't find any solutions. It will be so kind if you could help.
Thank you..
Related
I'm trying to sent an audio blob on some Google drive folder. To succeed I translate blob in file before sending it.
I received since the starting an error :
Error: File not found.
code: 404, errors: [ { domain: 'global',
reason: 'notFound',
message: 'File not found: 1aazd544z3FOCAsdOA5E7XcOaS3297sU.',
locationType: 'parameter',
location: 'fileId' } ] }
progressive edit : So far I have converted my audio blob in base64 string in order to ease the processing of my blob.
But, I fail always to write a file with my base 64 audio blob :
Here my driveApi.js :
// request data from req.body
var data = req.body.data ; // data variable is presented in form of base64 string
var name = req.body.word ;
(...)
// WRITE FILE AND STORE IT IN BODY HEADER PROPERTY
body: fs.writeFile((name + ".mp3"), data.substr(data.indexOf(',')+1), {encoding: 'base64'}, function(err) {
console.log('File created')
})
Three steps: create a temporary file with your base64 data out of the drive.files.create function, then give this file a specific name -e.g. tempFile, also you can customize this name with a time value. After that, pass this file on a "fs.createReadStream" method to upload it on Google drive.
Some hints:
Firstly - use path.join(__dirname, name + "-" + Date.now() +".ext" ) to create to file name
Secondly - make this process asynchronously to avoid data flow conflict (trying to create file before file is created), so call the drive.files.create after having setting a fs.writeFile function.
Thirdly - Destroy the tempFile after the operation has been done. It allows you to automatize the process.
I let you dive in the methods you need. But basically fs should do the job.
Again, be careful on the data flow and use callback to control it. Your code can crash just because the function gone up in a no-operational way.
Some links :
https://nodejs.org/api/path.html
https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback
here an instance :
// datavalue = some time value
fs.writeFile(
path.join(__dirname, name + "-" + datevalues +".mp3" ),
data.substr(data.indexOf(',')+1),
{encoding: 'base64'},
// callback
function(err) {
if(err){ console.log("error writting file : " + err)}
console.log('File created')
console.log("WRITTING") // control data flow
fileCreate(name)
})
function fileCreate (name){
// upload file in specific folder
var folderId = "someID";
var fileMetadata = {
'name': name + ".mp3" ,
parents: [folderId]
}; console.log("MEDIA") // control data flow
var media = {
mimeType: 'audio/mp3',
body: fs.createReadStream(path.join(__dirname, name + "-" + datevalues +".mp3" ))
};
drive.files.create({
auth: jwToken,
resource: fileMetadata,
media: media,
fields: 'id'
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log('File Id: ', file.data.id);
}
// make a callback to a deleteFile() function // I let you search for it
});
}
How about this modification? I'm not sure the condition of blob from reactApp.js. So could you please try to use this modification? In this modification, file or blob from reactApp.js are used.
Modified script :
var stream = require('stream'); // Added
module.exports.uploadFile = function(req){
var file ;
console.log("driveApi upload reached")
function blobToFile(req){
file = req.body.blob
//A Blob() is almost a File() - it's just missing the two properties below which we will add
file.lastModifiedDate = new Date();
file.name = req.body.word;
return file;
}
var bufStream = new stream.PassThrough(); // Added
bufStream.end(file); // Or bufStream.end(### blob from reactApp.js ###) Added
console.log(typeof 42);
// upload file in specific folder
var folderId = "1aa1DD993FOCADXUDNJKLfzfXcOaS3297sU";
var fileMetadata = {
"name": req.body.word,
parents: [folderId]
}
var media = {
mimeType: "audio/mp3",
body: bufStream // Modified
}
drive.files.create({
auth: jwToken,
resource: fileMetadata,
media: media,
fields: "id"
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log("File Id: ", file.id);
}
console.log("driveApi upload accomplished")
});
}
If this didn't work, I'm sorry.
I'm really lost when it comes to file uploading in meteor and manage the data between client and server.
I'm using Meteor Files from Veliov Group to upload multiple images on the client side. They're getting stored in a FilesCollection called Images and I have my Mongo.Collection called Adverts.
collections.js:
Adverts = new Mongo.Collection('adverts');
Images = new FilesCollection({
collectionName: 'Images',
storagePath: () => {
return `~/public/uploads/`;
},
allowClientCode: true, // Required to let you remove uploaded file
onBeforeUpload(file) {
// Allow upload files under 10MB, and only in png/jpg/jpeg formats
if (file.size <= 10485760 && /png|jpg|jpeg/i.test(file.ext)) {
return true;
} else {
return 'Limit 10mb';
}
}
});
// if client subscribe images
if (Meteor.isClient) {
Meteor.subscribe('files.images.all');
};
// if server publish images
if (Meteor.isServer) {
Images.allowClient();
Meteor.publish('files.images.all', () => {
return Images.collection.find();
});
};
What I'm trying to achieve is, when I upload the images, I wanna store the URLs on the document in Adverts that I'm working with (I'm using iron:router to access those documents _id).
I managed to get the URL but only for the first image uploaded, my code for what I saw on the docs:
Template.imageUpload.helpers({
imageFile: function () {
return Images.collection.findOne();
},
myImage: () => {
console.log(Images.findOne({}).link())
}
})
Template.imageUpload.events({
'change #fileInput': function (e, template) {
if (e.currentTarget.files) {
_.each(e.currentTarget.files, function (file) {
Images.insert({
file: file
});
});
}
}
})
I was using a Meteor.Call to send the URL to the server, but I couldn't manage to update the document with a new property pic and the value url of the image
server.js:
imageUpload: (actDoc, imgURL) => { // actDoc is the document id that I'm working on the client
Adverts.update({'reference': actDoc}, {$set: {'pic': imgURL}})
},
This is probably a dumb question and everything might in the docs, but I've readed those docs back and forth and I can't manage to understand what I need to do.
The answer for my problem was to do it server side
main.js server
FSCollection.on('afterUpload'), function (fileRef) {
var url = 'http://localhost:3000/cdn/storage/images/' + fileRef._id + '/original/' + fileRef._id + fileRef.extensionWithDot;
}
MongoCollection.update({'_id': docId}, { $set: {url: imgUrl }}})
I'm currently using Semantic-UI in a project. I use the search module to get the results from input. Here's my JavaScript code:
$('.ui.search')
.search({
apiSettings: {
action: 'search',
url: 'process.php?q={query}',
onSuccess(response, element, xhr){
console.log(response);
}
},
fields: {
results: 'songs', // array of results (standard)
title: 'title', // result title
url: 'videoID'
},
showNoResults: true,
onResults(response) {
console.log(response);
}
})
;
I get the JSON response from process.php. Here it is:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
header("Content-Type: application/json; charset=UTF-8");
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
throw new \Exception('please run "composer require google/apiclient:~2.0" in "' . __DIR__ .'"');
}
require_once __DIR__ . '/vendor/autoload.php';
// This code will execute if the user entered a search query in the form
// and submitted the form. Otherwise, the page displays the form above.
$videos = array();
// $videos["action"]["url"] = "youtube.com";
if (isset($_GET['q'])) {
/*
* Set $DEVELOPER_KEY to the "API key" value from the "Access" tab of the
* {{ Google Cloud Console }} <{{ https://cloud.google.com/console }}>
* Please ensure that you have enabled the YouTube Data API for your project.
*/
$DEVELOPER_KEY = 'MY_API_KEY';
$client = new Google_Client();
$client->setDeveloperKey($DEVELOPER_KEY);
// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);
try {
// Call the search.list method to retrieve results matching the specified
// query term.
$searchResponse = $youtube->search->listSearch('id,snippet', array(
'q' => $_GET['q'],
'maxResults' => 2
));
// Add each result to the appropriate list, and then display the lists of
// matching videos, channels, and playlists.
foreach ($searchResponse['items'] as $searchResult) {
switch ($searchResult['id']['kind']) {
case 'youtube#video':
$videos["songs"][] = array('title' => $searchResult['snippet']['title'], 'videoID' => $searchResult["id"]["videoId"]);
break;
}
}
} catch (Google_Service_Exception $e) {
die($e->getMessage());
}
}
echo json_encode($videos);
The problem is that once I start typing in the search input, nothing shows up, even though my JSON structure is valid. I have assigned the Semantic UI properties correctly. I'm following the standard JSON response that Semantic UI has suggested. Here's my JSON response
{
"songs":[
{
"title":"Wiz Khalifa - See You Again ft. Charlie Puth [Official Video] Furious 7 Soundtrack",
"videoID":"RgKAFK5djSk"
},
{
"title":"Wiz Khalifa - See You Again ft. Charlie Puth (MattyBRaps ft Carissa Adee Cover)",
"videoID":"Rpm8ZJuGEu4"
}
]
}
I've tried everything. It doesn't work. I would really appreciate your help
In my nativescript app, I'm able to record a video, but I want to upload it to an S3 bucket for later streaming. I'm running a node js server that handles the api for my app.
I'm trying to use the 'nativescript-background-http' library, but it always breaks when I try to run the uploadFile function.
Here's the relevant code:
var uploadVideo = function (filepath) {
console.log("Attempting to upload video...");
var session = bghttp.session("video-upload");
var filename = filepath.replace(/^.*[\\\/]/, '');
var request = {
url: config.apiUrl + 'upload',
method: "POST",
headers: {
"Content-Type": "video/mp4",
"File-Name": filename
},
description: "{ 'uploading': filename }"
};
try {
var task = session.uploadFile(filepath, request);
task.on("progress", logEvent);
task.on("error", logEvent);
task.on("complete", logEvent);
function logEvent(e) {
console.log("Logging event.");
console.dir(e);
console.log(e.eventName);
}
}
catch (error) {
console.dir(error);
console.log("An error occurred uploading the file. Removing video from filesystem...");
var documents = fs.knownFolders.documents();
var file = documents.getFile(filename);
file.remove()
.then(function (result) {
console.log("The video has been removed successfully.");
}, function (error) {
console.log("The video could not be removed from the file system.");
console.dir(error);
});
}
};
This is the output I end up with:
JS: Video located at /data/user/0/org.nativescript.Lifey/files/videoCapture_1486072596043.mp4
JS: Attempting to upload video...
JS: === dump(): dumping members ===
JS: {
JS: "nativeException": {
JS: "constructor": "constructor()function () { [native code] }"
JS: }
JS: }
JS: === dump(): dumping function and properties names ===
JS: === dump(): finished ===
JS: An error occurred uploading the file. Removing video from filesystem...
JS: The video has been removed successfully.
Any idea what's going on? Does 'nativescript-background-http' library even support video uploads (I've only seen image upload examples on their github)? Is there some alternative that I could use if I can't use that library?
Hello I'm using EAjaxUpload extension to upload files and its working perfectly and files are uploaded I want to add a description to each file. I used the onComplete to have the function here's my code :
$uploadfile = $this->widget('ext.EAjaxUpload.EAjaxUpload',
array(
'id' => 'uploadFile',
'config' => array(
'action' => Yii::app()->createUrl('objective/upload'),
'allowedExtensions' => array("docx", "pdf", "pptx"),//array("jpg","jpeg","gif","exe","mov" and etc...
'sizeLimit' => 5 * 1024 * 1024,// maximum file size in bytes
//'minSizeLimit'=>10*1024*1024,// minimum file size in bytes
'onComplete' => "js:function(id, fileName, responseJSON){
console.log(responseJSON);
var filedescription= prompt('file description');
if (filedescription != null) {
document.getElementById('demo').innerHTML =
filedescription;
return filedescription;
}
}",
//'messages'=>array(
// 'typeError'=>"{file} has invalid extension. Only {extensions} are allowed.",
// 'sizeError'=>"{file} is too large, maximum file size is {sizeLimit}.",
// 'minSizeError'=>"{file} is too small, minimum file size is {minSizeLimit}.",
// 'emptyError'=>"{file} is empty, please select files again without it.",
// 'onLeave'=>"The files are being uploaded, if you leave now the upload will be cancelled."
// ),
'showMessage' => "js:function(message){ alert(message); }"
)
));
Now I want to return var filedescription to upload action in controller. How can I do that?
Thanks,
1.onComplete is called after your upload request is already processed by "objective/upload" action. So you have possibility to ask and set description as parameter BEFORE request:
'onSubmit' => "js:function(id, fileName){
// add filedescriton to post parameters:
this.params.filedescription = 'some file description';
}"
In controller "objective/upload" action you can access it as $_POST['filedescription'].
2.Other possibility is to create separate action for saving description (and additional file processing...) and call it from onComplete:
In onComplete:
$.post( 'saveUploadedFileDescription', { filedescription: 'some file description', fileName: fileName } );
In controller:
actionSaveUploadedFileDescription($filedescription,$filename) {
// ....
}