Deleting a File from Storage after Download - ajax

I'm working on a media asset management system. I want the user to be able to fill out a form with file width, height, extension and colorspace, then transform the image and serve it back as a download.
I can get that to work by responding to the Post-Request with the URL of the newly created file.
What I want is for that file to be deleted after download or after some time.
(Or, preferably, a way to use laravels download() Response, which I apparently can't use inside an Axios/Ajax post request).
Thanks for your help :)

There are two ways you can do this.
Let's assume you have a file in storage/app/download.zip:
1. Because Laravel uses Symfony's HttpFoundation internally, you can use the deleteFileAfterSend method:
public function download()
{
return response()
->download(storage_path('app/download.zip'))
->deleteFileAfterSend(true);
}
2. Create a Terminable Middleware that deletes the file after the download response was prepared.
class StorageDownload
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
return $next($request);
}
public function terminate($request, $response)
{
\Storage::delete('download.zip');
}
}
You'll need to register the middlware and assign it to your route for it to work.
As for triggering the download using JavaScript, something as trivial as setting the window location will work:
axios
.post('files/export/' + file.id, formData)
.then(function() {
window.location = 'files/download/' + file.id
});
Don't worry, this will not navigate away from your current page, it will just trigger the download.

for me , i like to handle this case using cron
you can read details here
add any column to check it's been downloaded or not (e.g status with value 0 or 1)
and you can create accessor on your model to count the date diff
public function getRangeDateAttribute(){
$today = Carbon::now()->startOfDay();
$downloadDate = $this->created_at;
$datediff = $today->diffInDays($downloadDate);
return $datediff
}
then sample code inside task scheduling :
if($media->status == 1 || $media->rangeDate > 7 ){ //checking the status & range date passed specific days you wanted
do whatever you wanted here
}

Related

Laravel Send or Queue Mail depending on config setting

I am looking for a neat way to send or queue email depending on a config setting.
Right now I am having to do something like this everytime I send an email
$mailContent = new AccountNotification($account);
$mailObject = Mail::to($email);
if(config('app.queueemail')){
$mailObject->queue($mailContent);
} else {
$mailObject->send($mailContent);
}
There has to be a simpler way to do this so I don't have to repeat this code each time I want to send an email.
Extending #ceejayoz's comment, a simpler way could also be to use a global Helper function.
For example, you could have a send_email() global function that will send/queue email depending on your app's configuration.
if ( ! function_exists('send_email')) {
/**
* Sends or queues email
*
* #return mixed
*/
function send_email($mailer, $content)
{
return config('app.queueemail')
? $mailer->queue($content)
: $mailer->send($content);
}
}
To use it you would do:
send_email($mailer, $content);

Unable to replace files in request

I have an odd one.. I add an audio file, which is an existing file in the request
$file = $request->file('file')[0];
$request->files->add(['audio' => $file]);
When I do dd($request->files->all()) I see newly added 'audio' element. However when I do dd($request->allFiles()) I see original array.
I have even added a replace method for files to the Illuminate\Http\Request to replace $files with no luck.
public function replaceFiles($files) {
$this->files = $files;
}
Am I missing something?
It is as if $request->files and $this->files within $request are two different things.
Just noticed that the problem is with $this->convertedFiles within Illuminate\Http\Request which can be resolved by changing allFiles() to something similar to
/**
* Get an array of all of the files on the request.
*
* #return array
*/
public function allFiles()
{
$files = $this->files->all();
return $this->convertedFiles && count($this->convertedFiles) == count($this->files->all())
? $this->convertedFiles
: $this->convertedFiles = $this->convertUploadedFiles($files);
}
I've decided to extend App\Http\Requests\Request with adjusted allFiles() that I have mentioned above
You can use merge function to add new data into the request object.
$request->merge(['index_name' => $variable]);

How do I access non id property of request inside form requests?

I want to access route request parameters inside laravel form requests authorize. I cant find an example describing this.
// Works fine when you want id
dd($this->route('myResourceName'));
// How to do when I want something else???
dd($this->route('anotherAttribute'));
// Above give null probably because it is a resourceful controller
On a side note, I dont understand this design, whats the point?
$this->route('anyAttribute') would be the easiest, right?
Edit: more extensive example
class UpdateSlotAPIRequest extends APIRequest
{
public function __construct(){
parent::__construct();
$this->slot = Slot::find($this->route('slot'));
$this->access_token = $this->route('access_token'); // this is not working!
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// If administrator is logged in all is good.
// If slot is free its ok.
// If its not free but you provide good access_token its also fine.
return Auth::check() || $this->slot->isAvailable() || $this->slot->isValidAccessToken($this->access_token);
}
...
```
$access_token = request()->input('access_token');
Found it in https://laravel.com/docs/5.4/helpers

Can I use the Codeigniter redirect with probability?

We use a CMS, Fuel, built on Codeigniter, and use the redirect function often. I was wondering if there is a way to use probability with this function so that half (or whatever amount we set) the time it redirects to one page and half the time to another.
In general we will create a page with a redirect that looks like this:
<?=redirect('https://subdomian.onanotherserver.com/asdf')?>
We would love to make it looks similar:
<?=probabilityRedirect(0.5, 'https://subdomian.onanotherserver.com/asdf', 'https://subdomian.onanotherserver.com/jkl')?>
What would be the best way to go about this? Can we build off the redirect or just write a new function?
I would make a new function. Probably adding this to url_helper.php makes it the easiest to implement. Could be a stand-alone helper too but then you have to be certain url_helper is loaded.
if(!function_exists('randomRedirect'))
{
/**
* Randomized Header Redirect
*
* #param int $seed value optional
* #param array $list an indexed array of URL strings
* #return void
*/
function randomRedirect($seed = NULL, $list)
{
//list needs to be an array
if(!is_array($list OR ! isset($list)))
{
throw new Exception('randomRedirect() requires Array in second parameter');
}
if(!empty($seed))
{
mt_srand($seed);
}
$choice_count = count($list);
redirect($list[mt_rand(0, $choice_count)]);
}
}
Note: I did not test this! Results not guaranteed. :)
Revised code below.
Had some time to experiment with the above which eventually resulted in this.
randomURL_helper.php
<?php
if(!function_exists('p_redirect'))
{
/**
* Randomized Header Redirect
*
* #param array $list an indexed array of URL strings
* #param bool $seed optional when true, the random number generator will be seeded
*
* #return void
*
* Takes a list of URL strings in an array and randomly selects one as the
* input to the CodeIgniter function redirect.
* If you specify the full site URL that link will be built,
* but for local links simply providing the URI segments to the
* controller you want to direct to will create the link.
*
* The function will build the URL based on your config file values.
*
* This function requires the CodeIgniter helper "URL Helper"
* to be loaded using the following code: $this->load->helper('url');
*
* Use this line of code $this->load->helper('randomURL');
* to make p_redirect available to your CodeIgniter application.
*
*/
function p_redirect($list, $seed = FALSE)
{
if(!is_array($list))
{
// $list must be an array
throw new Exception('randomRedirect() requires Array as first parameter');
}
if($seed)
{
list($usec, $sec) = explode(' ', microtime());
$seed_val = (float) $sec + ((float) $usec * 100000);
mt_srand($seed_val);
}
redirect($list[mt_rand(0, count($list) - 1)]);
}
}
Tested it enough to see that it's not completely off-base.
Seems to get the job done. Enjoy!
You can just include it inside a rand 50/50 condition,
<?php
if (mt_rand(0,1)) {
redirect('https://subdomian.onanotherserver.com/asdf')
}
?>

Availability of $this->var in Phalcon\Mvc\View\Simple

I'm responsible for a rather large web app I built 8 years ago, then later refactored using ZF1 and now trying to move beyond that into more modern framework components. At the moment am trying to see if I can swap out Zend_View for Phalcon\Mvc\View\Simple without having to touch every .phtml file.
Problem I've run into is that while both assign a variable to the view in the same way (e.g. $this->view->foo = 'bar'), in Zend_View in the template you would <?=$this->foo;?> to print the var but in Phalcon it is <?=$foo;?>.
As I mentioned I don't want to go through each of several hundred .phtml files to remove $this->. Is there a way I can override Phalcon's render() or otherwise enable access to the view params using $this?
Here's what I came up with after fiddling with it all day. Simply extend the PHP view engine:
class Engine extends \Phalcon\Mvc\View\Engine\Php
{
/**
* Renders a view using the template engine
*
* #param string $path
* #param array $params
* #param boolean $mustClean
* #return string
*/
public function render($path, $params = null, $mustClean = null)
{
/**
* extract view params into current object scope
* so we can access them with <?=$this->foo;?>
* Maintains backward compat with all the .phtml templates written for Zend_View
*/
foreach($this->_view->getParamsToView() as $key => $val) {
$this->$key = $val;
}
return parent::render($path, $params, $mustClean);
}
You can use DI container to access any registered services in the view, so just put your variables into DI (in the action for example):
public function indexAction()
{
$this->getDi()->set('hello', function() { return 'world'; });
...
And then use it in the template via $this variable:
<div>
<?php echo $this->hello; ?>
</div>
P.S. This is not a good way to assign variables to the view, but should help in your particular case.

Resources