I'm trying to get ZipStream working in Laravel 5.4. I want to stream files from s3 to create a ZipStream which is returned to the browser.
Currently my code produces corrupt ZIP files the same size as valid ZIP files.
This is my action method:
public function mediaZip(User $user)
{
return response()->stream(function () use ($user) {
$zip = new ZipStream($user->name . ".zip", [
'content_type' => 'application/octet-stream'
]);
foreach ($user->media as $medium) {
$stream = Storage::disk("s3")->readStream($medium->location);
$zip->addFileFromStream($medium->name, $stream);
}
$zip->finish();
});
}
If I read each file into memory using the code below, the ZIP files work fine. This is however undesirable as I will be working with files that can be several gigabytes large.
public function mediaZip(User $user)
{
return response()->stream(function () use ($user) {
$zip = new ZipStream($user->name . ".zip", [
'content_type' => 'application/octet-stream'
]);
foreach ($user->media as $medium) {
$file = Storage::disk("s3")->read($medium->location);
$zip->addFile($medium->name, $file);
}
$zip->finish();
});
}
Can anyone help me figure out what's going wrong with the ZIP files?
Thanks!
Got it to work by specifying "store" for the storage_method param.
$zip->addFile($medium->name, $file, [], "store");
Related
posting this again because I didn't find to solution yet.
Laravel can't found the file storage/app/public/upload
when I usehttp://127.0.0.1:8000/storage/upload/The_fileName.x I get 404 not found
I've tried http://127.0.0.1:8000/storage/app/public/upload/The_fileName.x too.
what should I do ?
In DocumentController :
public function store(Request $request)
{
$request->validate([
'doc' => "required",...
]);
$document = new document();
$file = $request->file('doc');
$filename=time().'.'.$file->getClientOriginalExtension() ;
// I've tried these too, one by one and still get the same error .
//$file_path = public_path('public/upload');
//$file->move($file_path, $filename);
//Storage::disk('local')->put($file, $filename);
//request('doc')->store('upload', 'public');
$file->storeAs('public/upload', $filename);
$document->doc = $request->input('doc', $filename);
$document->candidate_id = $candidate_id;
$document->save();
Thank you in advance
According to Laravel document File Storage, you need to create a symbolic link at public/storage which points to the storage/app/public then you can access the file with http://127.0.0.1:8000/upload/The_fileName.x.
I want to make a private directory using Laravel 6.
Only users who have already logged in can access the directory.
So, I implemented below:
routes/web.php
Route::group(['middleware' => ['private_web']], function() { // 'private_web' includes auth
Route::get('/private/{path?}', 'PrivateController#index')->name('private')->where('path', '.*');
});
PrivateController.php
public function index(Request $request, $path = null) {
$storage_path = 'private/' . $path;
$mime_type = Storage::mimeType($storage_path);
$headers = [ 'Content-Type' => $mime_type, ];
return Storage::response($storage_path, null, $headers);
}
It is working.
But, when I got a html from the directory using Chrome, a css linked from the html wasn't applied (the css is in private directory and just downloaded successfully).
The cause is already known and it is Storage::mimeType returns 'text/plain' against css.
I can fix it by making a branch:
if (ends_with($path, '.css')) {
$mime_type = 'text/css';
} else {
$mime_type = Storage::mimeType($storage_path);
}
Question:
Is there more better solution?
I'm afraid of increasing such branch at each file type...
thanks.
I'm trying to figure out what is wrong with my validation, but I'm not sure.
I have created a file upload that uploads the file to S3. Works fine except when I need to validate python files.
In my FileUploadController.php I have a store(FileStoreRequest $request) method that handles the upload. I added the $validatedData = $request->validate(); in it and it works.
I have also added the mimes.php in config folder with the following:
<?php
return [
'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed'),
'py' => array('text/plain', 'application/x-python' , 'application/octet-stream, application/x-python-code, text/x-python-script', 'text/x-python'),
];
And the rules() method inside my FileStoreRequest class is
public function rules()
{
return [
'preprocessor' => 'mimes:py',
];
}
Any time I try to upload the python file I get the error
The preprocessor must be a file of type: py.
When I remove the mimes check from the rules() it passes.
The rules work, because I tested it on another view for zip file upload.
Any ideas what could be wrong?
You can create custom validation like:
$input = $request->all();
if (isset($input["preprocessor"]) && !empty($input["preprocessor"])) {
$filesource = $input["preprocessor"];
$fileExtension = $filesource->getClientOriginalExtension();
$input["ext"] = $fileExtension;
}
$rules = array(
'ext' => 'nullable|in:py',
);
I have a controller method like so:
use Symfony\Component\HttpFoundation\StreamedResponse;
public function downloadTransactions($type)
{
$this->authorize('download', Invoice::class);
$filename = 'invoices-' . strtolower($type) . '.csv';
$response = new StreamedResponse(function() {
Invoice::generateTransactionsCsv($type);
}, 200, [
'Content-Type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
]);
return $response;
}
and then in my Invoice model I am populating the file:
public static function generateTransactionsCsv($type = null)
{
// Open output stream
$handle = fopen('php://output', 'w');
// Add CSV headers
fputcsv($handle, [
'ID',
'REF',
'DESCRIPTION',
'DATE',
'AMOUNT',
]);
// Close the output stream
fclose($handle);
}
but I get an ERR_INVALID_RESPONSE in Chrome, although I would assume the browser doesn't matter. I've checked similar questions which suggest installing the zip extension but I already have it installed. Using PHP 7.1 locally. Also tried looking at the logs but there doesn't seem to be anything there (using Valet locally).
If I move the logic from the model to the controller then it works fine but my example above is simplified to just the header row of the csv, in reality, there's a bit more to it so I'd like to keep the logic in the model if possible.
I've also tried opening and closing the file handle in the controller and passing it the model but that didn't work either.
Looks like it was because the $type variable wasn't being passed correctly:
$response = new StreamedResponse(function() use ($type) {
....
}
Was able to figure it out thanks to Safari, it downloaded a csv with the Laravel error trace in it which was weird, I didn't think it would be any different from Chrome.
I have a file full of logs! I called them apache.logs.
So now I need to get them in Laravel and I don't know how.
I just want to save all logs in a variable ($logs) and view them.
public function getlogs ()
{
$logs = \Request::file('apache.log');
return view('logs' , [
'all_logs' => $logs
]);
}
This doesn't work and I don't know what I need to change.
If your using \Request::file then the file should come along with the request params, But here seems like you want to access a stored file in file system using laravel
to do that
ini_set('memory_limit','256M');
$logs = \File::get('apache.log');
return view('logs' , [
'all_logs' => $logs
]);
UPDATE
if you file is in root same like composer.json then you need to change the path to match with it like
ini_set('memory_limit','256M');
$path = base_path()."/apache.log"; //get the apache.log file in root
$logs = \File::get($path);
return view('logs' , [
'all_logs' => $logs
]);
wrap this in a try catch block for best practice, because in some case if apache.log not exists or not accessible laravel trow a exception, we need to handle it
try {
ini_set('memory_limit','256M');
$path = base_path()."/apache.log"; //get the apache.log file in root
$logs = \File::get($path);
return view('logs' , [
'all_logs' => $logs
]);
} catch (Illuminate\Filesystem\FileNotFoundException $exception) {
// handle the exception
}