I'm creating a downloads functionality with Laravel. When the user clicks on the 'download' button, I initiate an ajax call to the controller which looks like this -
public function download(Resource $resource) {
// Force download of the file
$file_to_download = 'https://data.domain.com/downloads/' . $resource->file_name;
$temp_file_location = public_path('/tmp_files/' . $resource->file_name);
copy($file_to_download, $temp_file_location);
return response()->download($temp_file_location)->deleteFileAfterSend(true);
}
Chrome's inspector shows that the response gets populated with the contents of the file, but it won't trigger the actual download.
I've been trying to find an answer, but have had no success so far. Would really appreciate your help.
Thank you for your time.
You cannot download a file from an Ajax request because Javascript is unable to save files to your filesystem out of security concerns.
There are a few good packages out there like Jquery File Download
Or you can use a traditional GET request.
Related
I wrote a simple script in plain PHP that uses $_FILES['uploadedfile']['tmp_name'] to fetch a freshly uploaded file and process its contents directly without permanently storing it. The idea is to allow the user to upload a file containing several rows of data that will be automatically parsed and added to a database by the PHP script. There is no need to store the file itself or a reference to it in the database as only the file contents are important. I know of Import CSV to MySQL, but I am trying to keep things clean and easy for the user (and for the time being I am developing with phpDesktop + sqlite so that my application will be portable).
I am now trying to recreate this process within Agile Toolkit but I cannot seem to figure out how. I know that the filestore model must access ['tmp_name'] before it moves/renames the file but I cannot figure out how to poach just this functionality. I tried looking in /lib/Form/Field/Upload.php to see if any of the methods there might be of use, but I am quite new to PHP so these docs are baffling to me. getFilePath() looked promising, but it seems that $_FILES remains empty when I do something like:
$form = $page->add('Form');
$upl = $form->addField('Upload', 'file');
$form->addSubmit();
if ($form->isSubmitted()){
$form->js()->univ()->alert($upl->isUploaded())->execute(); //sends js alert('false')
}
I realize that AJAX cannot be used to post files and I have a feeling this is part of the problem but I am not really sure where to go from here. Any help would sincerely be appreciated.
Thanks.
Agile Toolkit uploads file as soon as it is selected - moves it immediately into filestore and creates database record, so not really what you need.
Anything you write in a plain PHP can also work with Agile Toolkit. You can disable JavaScript in the form by doing this:
$this->add('Form',array('js_widget'=>false));
Such a form would send you a normal POST request.
Ok, I managed to achieve what I wanted by creating a custom extension of Form_Field_Upload and redefining the loadPOST() method within it.
function loadPOST(){
Form_Field::loadPOST();
if($_GET[$this->name.'_upload_action']){
// This is JavaScript upload. We do not want to trigger form submission event
$_POST=array();
}
if($_GET[$this->name.'_upload_action'] || $this->isUploaded()){
if($this->model){
try{
$model=$this->model;
/*Function is identical to parent above this line*/
//process file here and do $model->set('custom_field',$value);
//I am using $this->getFilePath() to analyze the uploaded file
/*Function is identical to parent below this line*/
$model->save();
}catch(Exception $e){
$this->api->logger->logCaughtException($e);
$this->uploadFailed($e->getMessage()); //more user friendly
}
$this->uploadComplete($model->get());
}
}
if($_POST[$this->name.'_token']){
$a=explode(',',$_POST[$this->name.'_token']);$b=array();
foreach($a as $val)if($val)$b[]=$val;
$this->set(join(',',filter_var_array($b,FILTER_VALIDATE_INT)));
}
else $this->set($this->default_value);
}
I sure this is not the most elegant solution but it worked for my purpose anyway.
I have a agile File input, im using the model File from addons, at the moment without any extend or modifications.
$f=$this->add('Form');
$modelo = $this->add($this->model);
$f->addField('upload','Upload_test','Upload Test')->setModel($modelo);
$elemento = $this->add('HtmlElement');
$t = $this;
$modelo->addHook('afterSave',function($m) use($t, $elemento)
{
$t->js(true)->univ()->alert('Uploaded!');
$elemento->set('Uploaded');
});
$f->onSubmit(function($f) use($t){
$t->js(true)->univ()->alert(333)->execute();
});
The callback are triggering but, any modifications to the actual html are failed, also any js like the simple alert saying Uploaded. How can I execute some PHP like $elemento->set('Uploaded'); to inform of the recently uploaded file? The JS with the alert also doesnt work :(
Any help would be apreciated
The upload element will have an event "upload" triggered as soon as upload is finished.
https://github.com/atk4/atk4/blob/master/templates/js/ui.atk4_uploader.js#L196
You can fetch data from element's data().
This is how I call the editor:
new nicEditor({
buttonList : ['bold','italic','underline','upload'],
iconsPath:'img/nicedit.png',
uploadURI : 'http://server.com/integracion/files/nicUpload.php'
}).panelInstance(textareaId);
And the .php file exists ( and I the one in the Docs, and I updated the target paths )
/* I want them here http://server.com/integracion/files/uploads/ so... */
define('NICUPLOAD_PATH', './uploads'); // Set the path (relative or absolute) to
// the directory to save image files
define('NICUPLOAD_URI', '/uploads'); // Set the URL (relative or absolute) to
// the directory defined above
But I on response when upload completes (and of corse an alert from nicedit..)
<script>
try {
top.nicUploadButton.statusCb({"error":"Invalid Upload ID"});
} catch(e) { alert(e.message); }
</script>
what am I missing?
-EDIT
I think the problem might be in the php file:
$id = $_POST['APC_UPLOAD_PROGRESS']; /* APC is installed and enabled */
if(empty($id)) {
$id = $_GET['id'];
}
FINAL EDIT:
I have managed to make this work!
Here is an working example:
http://simplestudio.rs/yard/nicedit/
Uploaded images are going to be stored here:
http://simplestudio.rs/yard/nicedit/images/
And here is the whole code, just unpack it and put on your server, mainly I needed to adjust nicEdit.js because it had some issues.
http://simplestudio.rs/yard/nicedit/nicedit.rar
Just make your code with that js file and by looking at my example, it will work :)
Also you need to have php APC installed so that this script can work:
http://php.net/manual/en/apc.installation.php
If you by any mean have some problems I am here to solve it.
I will not delete this example on my server so that everybody who have this issue can freely download it...
The code responsible for image upload is the method uploadFile, it is looking for uploadURI option parameter.
You will need to modify onUploaded event handler to parse your custom response instead of the imgur's one (sample). By default it expects at least {"upload": { "links": {"original": "http://..."}, "image": {"width": "123" } }}.
I'm sorry but I can't help with the FormData() handling server side with PHP.
For more information you can try out the demo page on the nicEdit web site using Firebug or WebInspector to snoop the network requests, and, of course, the source code.
I have a music player that links to a song using the following syntax:
<li>title</li>
Is there any way that I could have that executed server side and then be displayed like (see below) for the user?
While searching, I ran across this...I like the idea behind having an external file that has the data...like:
<?php
// get-file.php
// call with: http://yoururl.com/path/get-file.php?id=1
$id = (isset($_GET["id"])) ? strval($_GET["id"]) : "1";
// lookup
$url[1] = 'link.mp3';
$url[2] = 'link2.mp3';
header("Location: $url[$id]");
exit;
?>
then using: http://yoururl.com/path/get-file.php?id=1 as the link...the only problem is that when you type http://yoururl.com/path/get-file.php?id=1 the user goes straight to the file...is there any way to disable that ability...maybe some code on get-file.php itself?
Ok, so I did a combination of things that I am satisfied with...although not completely secure, it definitely helped me obscure it quite a bit.
First of all, I am using the AudioJS player to play music - which can be found: http://kolber.github.com/audiojs/
Basically what I did was:
Instead of using "data-src" as the path to my songs I called it "key", that way people wouldn't necessarily think it was a path.
Instead of using "my-song-title" as the name of the songs, I changed it to a number like 7364920, that way people couldn't look for that in the source and find the url that way.
I added + "mp3" to the javascript code after all of the "key" variables, that way I would not have to declare it in obfusticated link.
I used a relative path like "./8273019283/" instead of "your-domain.com/8273019283/", that way it would be harder to tell that I was displaying a url.
Added an iTunes link to the href, that way people might get confused as to how I was pulling the file.
So, now my inline javascript looks like:
<script type="text/javascript">
$(function() {
// Play entire album
var a = audiojs.createAll({
trackEnded: function() {
var next = $("ul li.playing").next();
if (!next.length) next = $("ul li").first();
next.addClass("playing").siblings().removeClass("playing");
audio.load($("a", next).attr("key") + "mp3");
audio.play();
}
});
// Load the first song
var audio = a[0];
first = $("ul a").attr("key") + "mp3";
$("ul li").first().addClass("playing");
audio.load(first);
// Load when clicked
$("ul li").click(function(e) {
e.preventDefault();
$(this).addClass("playing").siblings().removeClass("playing");
audio.load($('a', this).attr('key') + "mp3");
audio.play();
});
});
</script>
My link looks like:
Falling
When you load it up in the browser and you view the source you'll see:
Falling
Then when you use Web Inspector or Firebug you'll see:
Falling - *which doesn't completely give the url away
Basically what I did was make the link look like it's an api-key of some-kind. The cool thing is that you can't just copy the link straight from view source or straight from Web Inspector/Firebug. It's not fool-proof, and can definitely be broken, but the user would have to know what they're doing. It keeps most people away, yet still allows the player to get the url it needs to play the song :)
*also, I got the php obfusticate script from somewhere on Stack Exchange, just not sure where.
Instead of doing a header redirect, add proper headers and include the audio file in your PHP code. Then, in your .htaccess file, you can disallow access to the directory where your audio files live.
If you are using amazon s3 service you can use signed url for your files. It will be more safe as you have to be signed user and also url can be expired. Read this.
No. This is not possible since it is the browser that interprets the HTML to make the page work properly. So if the client (browser) does not know where the mp3 is coming from then it will not be there to use.
On the other hand if you want to have the music switch songs by clicking a link then i suggest you look into some tools like http://jplayer.org/
EDIT: The only way to probably prevent direct access to the file itself would be to read the file in instead of linking to it from the script. For instance on my image hosting site http://www.tinyuploads.com/images/CVN5Qm.jpg and if you were to look at the actual file path on my server, the file CVN5Qm.jpg is out of view from the public_html folder. There is no way to directly access the file. I use databases to take the image id, look up where it is stored, and then readfile() it into the script and display the proper headers to output the image.
Hope this helps
I use http_referer and I can controll the procedence of the link
<?php
// key.php
// call with: http://yoururl.com/path/key.php?id=1
$page_refer=$_SERVER['HTTP_REFERER'];
if ($page_refer=="http://www.yourdomine.com/path/page.html")
{
$id = (isset($_GET["id"])) ? strval($_GET["id"]) : "1";
// lookup
$url[1] = 'link1.mp3';
$url[2] = 'link2.mp3';
header("Location: $url[$id]");
exit;
}
else
{
exit;
}
?>
I want to send a request to my Zend AMF to Open a Dialogue Box for a File Download.
The process:
Send a request to the Zend Server from my flash App, process the MYSQL results with PHP, then send the result to the browser as a file download (.csv) AND a result true or false to the app
I have the code working just fine outside of the Zend Environment, but of course, when i go to echo/print the file - it sends back to flash with nothing happening.
Is there any way around this?
$file = "";
$outtype = "Content-type: application/octet-stream";
header($outtype);
$outtype = 'Content-disposition: attachment; filename="file.csv"';
header($outtype);
$stmt->bind_result($id, $username, $email, $location);
while($stmt -> fetch()){
$file .= '"'.addslashes($col1).'"';
$file .= ',"'.addslashes($col2).'"';
$file .= ',"'.addslashes($col3).'"';
$file .= "\n";
}
print $file;
exit;
Or, do i have to just request this outside of the zend request...?
So far i have changed the headers to make use of the zend headers:
$this->setHeader('Content-Type', 'application/octet-stream');
$this->setHeader('Content-disposition:', 'attachment');
$this->setHeader('filename:', 'file.csv');
But am unsure how to the attach $file to 'file.csv' and then return a result of true to Flash AND download the file.. (zend noob here i am afraid..)
Are you using Zend MVC? If so make sure you are not rendering a layout....
I am not too happy with the exit; statement... since zend uses an mvc framework, it builds the response and renders it. Causing the script to exit might mean the content does not get rendered properly.
Also, make sure you use the correct zend functions to build the headers, it is very possible that zend is adding conflicting headers to the response. See http://framework.zend.com/manual/en/zend.controller.response.html
The process could be :
-1 Send a request to Zend Framework
-2 Query Mysql, process the result & write the file to the server
-3 Zip the file
-4 return the file url to Flash
-5 inform the user that the file is ready for download
-6 a user click calls navigateToURL from Flash, using the returned url
Since it's a zip file url, the browser should open a dialog box.
According to this excerpt from the docs, it seems that your options are fairly limited, as it's not only a Flash issue...
In Flash Player 10 and later running in a browser, using this method
programmatically to open a pop-up window may not be successful.
Various browsers (and browser configurations) may block pop-up windows
at any time; it is not possible to guarantee any pop-up window will appear.
However, for the best chance of success, use this method to open a
pop-up window only in code that executes as a direct result
of a user action (for example, in an event handler for a
mouse click or key-press event.)