I'm trying to merge a file chunked in parts and in Laravel Framework 7.30.4 is not working the append method of Storage/File Facade
foreach($files as $file)
{
$content = Storage::get($file);
Storage::append($tmp_file, $content);
}
When I do it with vanilla php works fine:
foreach($files as $file)
{
$content = Storage::get($file);
file_put_contents(storage_path("app/{$tmp_file}"), $content, FILE_APPEND);
}
the md5 hash results is only correct with the vanilla style, what I'm doing wrong in laravel style?
I'm watching with vbindiff tool and the all the file is equal except the last part.
thank you
I see this code in laravel code:
public function append($path, $data, $separator = PHP_EOL)
{
if ($this->exists($path)) {
return $this->put($path, $this->get($path).$separator.$data);
}
return $this->put($path, $data);
}
Solved using NULL as separator:
foreach($files as $file)
{
$content = Storage::get($file);
Storage::append($tmp_file, $content, NULL);
}
Related
This question already has an answer here:
File uploading in Laravel
(1 answer)
Closed 3 years ago.
Been working on this problem for 2 days and still cannot figure it out. I am trying to upload multiple files into storage in my Laravel project. I know my code works up to the foreach as I tested this with dd.
My controller:
$files = $request->file('current_plan_year_claims_data_file_1');
$folder = public_path(). "\storage\\$id";
if (!File::exists($folder)) {
File::makeDirectory($folder, 0775, true, true);
}
if (!empty($files)) {
foreach($files as $file) {
Storage::disk(['driver' => 'local', 'root' => $folder])->put($file->getClientOriginalName(), file_get_contents($file));
}
}
I see that you are trying to store the files directly in public folder, but why not use the Storage API of Laravel and use the public disk? You can do something like this to upload the files to the public directory:
$id = 123;
$files = $request->file();
$folder = $id;
if (count($files) > 0) {
foreach ($files as $file) {
$file->store($folder, ['disk' => 'public']);
}
}
And be sure that you have linked the storage path to public:
php artisan storage:link
Focus on $files = $request->file(); line. When you don't pass an argument to file() method, all uploaded file instances are returned. Now when you will loop over the $files array, you will get access to individual uploaded files.
And then you can store the file using your logic, i.e. you can use the original name or whatever else. Even you can use the Storage facade to process the file instance.
i.e. if you want to store the files with their original names, I find this a cleaner way rather than what you are doing:
$id = 123;
$files = $request->file();
$folder = $id;
if (count($files) > 0) {
foreach ($files as $file) {
Storage::disk('public')->putFileAs(
$folder,
$file,
$file->getClientOriginalName()
);
}
}
And as suggested by #cbaconnier, you can use allFiles() method too that's more descriptive:
$files = $request->allFiles();
I hope this helps.
You're trying to iterate over files, and file is just a reference to request->file(), which is a SINGLE UploadedFile object.
As indicated by your comment, you have multiple file inputs with different name attributes, so you can't easily loop over them with one statement, eg: if you had multiple files all uploaded as "attachments[]" as the input name attribute, you could get them all with $request->allFiles('attachments'), however, if you want to keep the input names as they are, this should be close to what you want.
public function foo(Request $request, $id){
$folder = public_path(). "\storage\\$id";
if (!File::exists($folder)) {
File::makeDirectory($folder, 0775, true, true);
}
$files = array();
$files[] = $request->file('current_plan_year_claims_data_file_1');
$files[] = $request->file('prior_plan_year_claims_data_file_1');
$files[] = $request->file('etc_file_whatever');
foreach($files as $file) {
Storage::disk(['driver' => 'local', 'root' => $folder])->put($file->getClientOriginalName(), file_get_contents($file));
}
}
Side note, i'm not sure what you're doing with File and public_path, but if your goal is just to put something in your app storage, something like this should work fine
public function foo(Request $request, $id){
if(!\Storage::exists($id)){
\Storage::makeDirectory($id);
}
$files = array();
$files[] = $request->file('current_plan_year_claims_data_file_1');
$files[] = $request->file('prior_plan_year_claims_data_file_1');
$files[] = $request->file('etc_file_whatever');
foreach($files as $file) {
\Storage::put("$id/" . $file->getClientOriginalFileName(), $file);
}
}
I want to update user image but it's not getting updated.
I tried with $request->hasFile('image') but when I return these statement it always returns false
here is my controller
if($request->hasFile('image'))
{
$file = $request->file('image');
$file->move(public_path().'/image/',$file->getClientOriginalName());
$file_name = $file->getClientOriginalName();
DB::table('settings')
->where('id', $id)
->update(['logo' => $file_name]);
}
when I write
return response()->json($request->hasFile('image'));
it will return always false
try use this one instead
if ($request->file('image')) {
// your image upload code here
}
i am using the following codes to make zip and allow user to download the zip
but its not working.it shows the error as ZipArchive::close(): Read error: Bad file descriptor.What might be the problem?i am working with laravel.
public function downloadposts(int $id)
{
$post = Post::find($id);
// Define Dir Folder
$public_dir = public_path() . DIRECTORY_SEPARATOR . 'uploads/post/zip';
$file_path = public_path() . DIRECTORY_SEPARATOR . 'uploads/post';
// Zip File Name
$zipFileName = $post->post_title . '.zip';
// Create ZipArchive Obj
$zip = new ZipArchive();
if ($zip->open($public_dir . DIRECTORY_SEPARATOR . $zipFileName, ZipArchive::CREATE) === TRUE) {
// Add File in ZipArchive
foreach ($post->PostDetails as $postdetails) {
$zip->addFile($file_path, $postdetails->file_name);
}
// Close ZipArchive
$zip->close();
}
// Set Header
$headers = [
'Content-Type' => 'application/octet-stream',
];
$filetopath = $public_dir . '/' . $zipFileName;
dd($filetopath);
// Create Download Response
if (file_exists($filetopath)) {
return response()->download($filetopath, $zipFileName, $headers);
}
return redirect()->back();
}
For Laravel 7.29.3 PHP 7.4.11
Create a GET route in api.php
Route::get('/downloadZip','ZipController#download')->name('download');
Create controller ZipController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use File;
class ZipController extends Controller
{
public function download(Request $request)
{
$zip = new \ZipArchive();
$fileName = 'zipFile.zip';
if ($zip->open(public_path($fileName), \ZipArchive::CREATE)== TRUE)
{
$files = File::files(public_path('myFiles'));
foreach ($files as $key => $value){
$relativeName = basename($value);
$zip->addFile($value, $relativeName);
}
$zip->close();
}
return response()->download(public_path($fileName));
}
}
In the public folder make sure you have a folder myFiles. This snippet will get every file within the folder, create a new zip file and put within the public folder, then when route is called it returns the zip file created.
Only pure php code.
public function makeZipWithFiles(string $zipPathAndName, array $filesAndPaths): void {
$zip = new ZipArchive();
$tempFile = tmpfile();
$tempFileUri = stream_get_meta_data($tempFile)['uri'];
if ($zip->open($tempFileUri, ZipArchive::CREATE) !== TRUE) {
echo 'Could not open ZIP file.';
return;
}
// Add File in ZipArchive
foreach($filesAndPaths as $file)
{
if (! $zip->addFile($file, basename($file))) {
echo 'Could not add file to ZIP: ' . $file;
}
}
// Close ZipArchive
$zip->close();
echo 'Path:' . $zipPathAndName;
rename($tempFileUri, $zipPathAndName);
}
I will suggest you to use Zipper package
Try below code for creating zip of multiple files :
public function downloadZip($id)
{
$headers = ["Content-Type"=>"application/zip"];
$fileName = $id.".zip"; // name of zip
Zipper::make(public_path('/documents/'.$id.'.zip')) //file path for zip file
->add(public_path()."/documents/".$id.'/')->close(); //files to be zipped
return response()
->download(public_path('/documents/'.$fileName),$fileName, $headers);
}
you can use the following code
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\ImgUpload;
use ZipArchive;
use File;
class UserController extends Controller
{
/**
* Function to get all images from DB
*/
public function downloadZip()
{
$data = ImgUpload::all();
foreach($data as $key => $value)
{
$imgarr[] = "storage/image". '/' . $value->image;
}
$ziplink = $this->converToZip($imgarr);
return $ziplink;
}
/**
* Function to covert all DB files to Zip
*/
public function converToZip($imgarr)
{
$zip = new ZipArchive;
$storage_path = 'storage/image';
$timeName = time();
$zipFileName = $storage_path . '/' . $timeName . '.zip';
$zipPath = asset($zipFileName);
if ($zip->open(($zipFileName), ZipArchive::CREATE) === true) {
foreach ($imgarr as $relativName) {
$zip->addFile($relativName,"/".$timeName."/".basename($relativName));
}
$zip->close();
if ($zip->open($zipFileName) === true) {
return $zipPath;
} else {
return false;
}
}
}
}
you can refer this link for more information
The question got answer, but I am posting this solution for those who wants to download dynamically zip some (based on id) files from the same folder, I hope it might help them that how to create dynamic zip file of multiple files/images affiliated with some id.
I would be taking example of multiple images. You can do the same for files.
Assuming the above table the autos_id is foreign key and based on the autos_id, there are multiple images store in the database.
To make zip file of it I will do the following:
public function downloadZip($id)
{
$data = AutoImage::where('autos_id',$id)->get();
$imgarr=[];
foreach($data as $data){
$file = storage_path() . '/app/public/autoImages/'.$data->image_name;
if(\File::exists(public_path('storage/autoImages/'.$data->image_name))){
$imgarr[]= public_path('storage/autoImages/'.$data->image_name);
}
}
$zip = new ZipArchive;
$fileName = 'AutoImages.zip';
/*OVERWRITE will not make a different zip file on server but it will
replace the one which is in the server, this approach will help you to not
make multiple zip files, if you want to creat new you can do it with unique
name of the zip file and adding CREATE instead of OVERWRITE.*/
if ($zip->open(public_path($fileName), ZipArchive::OVERWRITE) === TRUE)
{
$files = $imgarr; //passing the above array
foreach ($files as $key => $value) {
$relativeNameInZipFile = basename($value);
$zip->addFile($value, $relativeNameInZipFile);
}
$zip->close();
}
return response()->download(public_path($fileName));
}
Note: for file storage I used storage and then made a link symlink for storing files.
For further info of file storage: https://laravel.com/docs/9.x/filesystem
This works for me, multiple files zip and download.
public function download_attachment($ticket_no)
{
$zip = new \ZipArchive();
$fileName = $ticket_no.'.zip';
if ($zip->open(public_path($fileName), \ZipArchive::CREATE)== TRUE)
{
$files = File::files(public_path('uploads/tickets/' . $ticket_no));
foreach ($files as $key => $value){
$relativeName = basename($value);
$zip->addFile($value, $relativeName);
}
$zip->close();
}
return response()->download(public_path($fileName));
}
I want to export searched data to the laravel below is my controller
public function getUsageData(Request $request)
{
$start_date = $request->get('start_date');
$end_date = $request->get('end_date');
$particulars = DB::table('particulars')
->join('reqs', 'particulars.particular_id', "=", 'reqs.particular_id')
->whereBetween('date_applied', [$start_date, $end_date])
->select('particulars.item_name', 'particulars.unit', 'particulars.price', 'reqs.quantity_issued',
DB::raw('particulars.price*reqs.quantity_issued AS total_cost'))
->get();
if ($particulars->isEmpty()) {
return "No Records Found...................... ";
} else {
$pdf = PDF::loadView('issuer.getUsageReport', ['particulars' => $particulars]);
return $pdf->stream('getUsageReport.issuer');
}
}
I want to retrieve those data to the excel instead of pdf please help
Replace the two PDF lines in the else { ... } statement with:
$list = $particulars->toArray();
//This line adds headers if present in your data
array_unshift($list, array_keys($list[0]));
$callback = function() use ($list) {
$FH = fopen('php://output', 'w');
foreach ($list as $row) {
fputcsv($FH, $row);
}
fclose($FH);
};
return response()->streamDownload($callback,"filename.csv");
Depending on the structure of particulars you may need to do some manipulation to the data first, e.g. flattening. Comment below if so.
I need a code sniffer for converting all the variables in all of my PHP file from snake_case to camelCase.
I don't need the functions which do it in php on a string, I want to convert the variables in my PHP files to camelCase.
I appreciate you in advanced.
I found a way to do it.
I integrate the code for cakePHP (There is the file with ctp extension and the variable passed to view by set function).
Save the below code as tocamelcase.php
php tocamelcase.php the/path/of/your/app
file content:
<?php
function snakeToCamel($val) {
preg_match('#^_*#', $val, $underscores);
$underscores = current($underscores);
$camel = str_replace('||||', '', ucwords(str_replace('_', '||||', $val), '||||'));
$camel = strtolower(substr($camel, 0, 1)).substr($camel, 1);
return $underscores.$camel;
}
function convert($str) {
global $j;
$name = '/(\$[a-zA-Z0-9]+_[a-zA-Z0-9_]+)|'.
'(->[a-zA-Z0-9]+_[a-zA-Z0-9_]+)|'.
'(::[a-zA-Z0-9]+_[a-zA-Z0-9_]+)|'.
'(\sfunction\s+[a-zA-Z0-9]+_[a-zA-Z0-9_]+)|'.
'(\$this->set\(\'[a-zA-Z0-9]+_[a-zA-Z0-9_]+\'\,)|'.
'(\$this->set\(\"[a-zA-Z0-9]+_[a-zA-Z0-9_]+\"\,)'.
'/i';
$str = preg_replace_callback($name, function($matches){
return snakeToCamel($matches[0]);
},$str);
return $str;
}
$path = $argv[1];
$Iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
$i=1;
foreach($Iterator as $file){
if(substr($file,-4) !== '.php' && substr($file,-4) !== '.ctp')
continue;
echo($i.": ".$file."\n");
$i++;
$out = convert(file_get_contents($file));
file_put_contents($file, $out);
}