I'm looking at the DownloadItemView class and I'm trying to understand how it manages to send custom HTTP headers to the client. From what I understood, the photo.tpl template creates a link to the DownloadItem view which then handles the HTTP header creation. However, I cannot do the same in my custom module, although I have copied the code from the DownloadItemview class and modified it for my needs. It's identical except for the "Content-Disposition" header.
This is how I think it works:
1. user clicks downloaditemview link
2. the renderImmediate function makes sure the requested item data is valid and calls _sendFile() which sends the file
3. _sendFile() makes sure the user has the appropriate permissions, sends the custom HTTP header and then the binary data.
Is there a step I am missing which the DownloadItem class does? Any help will be appreciated!
Posts: 4342
what is your code doing then?
Posts: 13
It does nothing after it sent the binary data, just like the DownloadItem view class.
Posts: 4342
I mean, you haven't explained your problem very well.
Perhaps if you elaborate on that someone might be able to provide some help.
Posts: 13
I'm not asking about my custom module but I'd like to understand the DownloadItem view class. I hope I can solve my problem myself once I understood DownloadItem view.
Posts: 4342
What is it that you don't understand about the class?
Posts: 13
Posts: 4342
You know, for someone who's asking for support you might trying being a bit less "smart", and bit more keen to help those who are prepared to help you.
I'm looking at DownloadItem.inc now, and its use of the $phpVm seems fairly straightforward. It sends a custom header every time you call $phpVm->header(...) as you can verify by looking at GalleryPhpVm.class file. I can't believe that you haven't already worked that out, so I'm at a loss to understand what kind of extra understanding you're asking for.
So, let me ask again - I could quote myself but I won't descend to it - what is it that you don't understand about the class?
Posts: 13
I have worked out that $phpVm->header() sends headers of course, however my module doesn't do that. It sends out "text/html" for the content-type when instead binary data is being sent. I know the renderImmediate function is meant for such modules that are supposed to deliver custom output and thus custom headers. As far as I know I have shaped my module exactly after the Downloaditem class, but the Downloaditem class must have do something different that I cannot derive from looking at the code alone.
I understand, once the user clicks on the link to download an image, the Downloaditem view is the only "code" involved in delivering this image, correct? Or are there other steps before the Downloaditem class?
Posts: 4342
No, all gallery accesses (including a url with ...g2_view=core.DownloadItem... in it) go through main.php, so obviously there's more code than just one class involved.
The content type is sent in this line, in _sendFile(...):
and $data['mimeType'] is previously derived via this line, in the class's renderImmediate function:
Posts: 13
Of course I know that main.php is a vital part of every gallery2 process. What I meant was that at some point DownloadItem gets "control" over the HTTP header output and I wonder what it does in order to get to that point. I think I have understood the DownloadItem code but I must be missing something else that's not part of DownloadItem which causes my problems.
About the mime type: yes I know what DownloadItem does in order to determine the mime-type out of the gallery item. I have specified the HTTP header Content-type according to my output data but still the client receives the text/html header.
So I'm searching for something else in the gallery2 code (but not it in DownloadItem) which permits DownloadItem to manipulate the HTTP headers. I'd be thrilled to learn what that could be
Posts: 4342
No - it just outputs the headers one by one, in real time, so to speak, each time the header(...) function is called. The phpVm->header(..) function directly calls the php function header(). Nothing more complicated than that.
There's nothing that sophisticated.
Do some basic debugging, change the code in obvious ways, print strings to the output, change the headers at the point you think they're being output to a bit of random text to make sure that's where they're coming from, follow the excution flow with echo statements etc. Usual stuff.
EDIT: thought: see the php page http://uk2.php.net/header which has this comment "The optional replace parameter indicates whether the header should replace a previous similar header,..." - maybe you're somehow sending two sets of headers in error?
Posts: 13
After days that turned into weeks of searching and questioning myself I finally found the solution to my problem and it's quite stupid IMO My module.inc file had two newlines at the end. That would prevent my header() calls from working as expected. After I removed the newlines (by incident I have to add) the module worked and the headers got changed as expected.
I don't know if this is a "feature" or security measure or a bug but I hope I will save someone else the time of dealing with this problem.
Posts: 4342
It's neither a bug nor a security feature - it's correct operation. If you include even a single character (including whitespace) before the opening "<?php" or after the closing "?>" of any .php or .inc file then php sends that/those characters directly as output, as if it were regular html.
Once output is sent, it's too late to call header(..) http://uk.php.net/header contains this in pretty much the first paragraph:
If you are displaying errors in php (such as by putting Gallery into debug mode), you get a "headers already sent" warning in the output stream. It also shows up in the php/apache error log.
Glad you found the problem.