How to return a file via Web Service

Anthony picture Anthony · Aug 16, 2009 · Viewed 8k times · Source

I am working on a Web Service where the user would input parameters and have the option of have the data returned in various file formats (xml, html (on screen), csv, etc.).

If the server generates the file content (and therefor there is no actual file), then returning a URL to the file is not an option. So how can this be done? I know there are xml attributes to indicate that the data within an element is binary, but that won't trigger the browser to download the data as a file.

Is there some equivalent of Content Disposition for XML/Web Services?

On a very related note:

Can javascript/AJAX trigger a browser to download a file? I know that js alone doesn't have the ability to "generate" files (in the sense that the browser will download a string as a file with a given file name" but what if an ajax function calls a script and the script reply has Headers set to download?

I'll experiment with that last part, but would like to know if there is any solid info already out there.


More Details:

First, thank you to everyone who has responded. All of the answers have been really helpful and educational.

I thought I might try to explain a bit more about the situation to tie up all of the comments/concerns/suggestions that span the answers.

I manage a project for an internal staff web site. The project deals mainly with schedule viewing and modification. There are at least 4 different PHP scripts which query a MySQL DB for essentially the same data. The queries vary slightly based on the context. In one case it pulls a daily schedule which groups by the assignment, in another it queries a full week's schedule and groups by person. In yet another it queries for just one person's weekly schedule. In some it outputs data like hourly totals per person or day or position, and in others it just gives what is stored in the DB.

I have started to feel guilty about certain aspects of the project. Obviously I can combine a lot of the data fetching into one included script. I probably ought to be using object-oriented PHP to handle the results. And I have been more focused on making this mess work than making sure the data is safe and secure and that the stress on the DB is minimal and optimized. I'm not even sure how to really know if the queries ARE optimized.

And in addition to the above mentioned guilt, I've really started to get confused. In trying to neaten things up, I've found myself tangled up in a knot where one fix screws up something that was working fine.

So, I thought a good solution would be to create a Web Service that would simplify the entire process and force me to have a logic (an API, even) to how the data is fetched, and would be more useful for anyone who tried to take over when I eventually am not the lead developer. Plus it would make the whole thing more portable, for both upgrades and shifts in the site's back-end (some day it might be on a Windows server using Cold Fusion but I shudder at the thought) and for other software that may want to connect with the database.

But here's the rub:

The entire genesis of this project was based on the fact that our previous scheduling solution was to upload the very ugly and non-semantic HTML report generated by the very expensive enterprise-level scheduling software we use. The number one problem we had with this hideous HTML report and the software that generated it was that there was no option for a .ics "icalendar" file that we could import into Outlook or Google Calendar. I made it my personal mission to figure out a way to turn those awful reports INTO ics files, and thus begins the story on why I started learning PHP, regex, and MySQL.

So, if you aren't bored and asleep yet, I think a Web Service is the best option for simplifying and streamlining the schedule process, but if I end up having to use plain PHP/MySQL to get the most valuable part of the data (the calendar files) then I'm inclined to just ditch the whole thing and keep untangling the knot.

I do understand, by the way, that the script that uses the Web Service can create the ics file and that the AJAX can simply be avoided when that is what the user is requesting. Again, thanks to all that have made this more clear to me. I just want the web service to handle everything returned by the DB as possible on its end to have a sense of a clear partition between the HTML/JS/PHP and the database.

Thanks again!

Answer

nicholaides picture nicholaides · Aug 16, 2009

To have the browser download the file, you can do this:

window.location = "http://example.com/webservice-file-url";

And use the header:

Content-Disposition: attachment; filename="filename.ext"

If you want the user to choose between viewing on-screen and downloading, just use a conditional:

if (requested_format == 'html') {
    //get an html version and show it on screen
    ajaxRequestForHTML();
} else {
    //download the file
    window.location = "http://example.com/webservice-file-url";
}