After much head-scratching and experimentation, I finally figured out that the problem was on the Flash side of the equation. I'm playing back the videos with an FLVPlayback component inside Flash, but loading files with the PHP method I was trying doesn't work with the FLVPlayback component. It does work with the less robust Video component, but even using that component, the FLV won't progressively load into the component like it does when you load the file directly from Flash, which is causing problems with creating user-friendly loading bars.

To say I'm disappointed with Flash would be an understatement. Nevertheless, the input I received from this board was much appreciated. And hopefully the findings in this thread will save someone else similar aggravation.

    I'm not ready to blame Flash just yet. From the client side perspective, how the data is served out should be transparent. (Or should be able to be made transparent).

    I mean, technically, you could create a directory and create an .htaccess file entry that tells Apache to parse .flv files for PHP. Then change the name of your PHP file from resource.php to resource.flv and, assuming you put out the correct headers, how could the client side flash player know that you aren't actually serving a movie called resource.flv. I mean, data is data.

    By the way, I always use, @readfile($file); not readfile($file);
    According to the manual, it looks like one errors more gracefully - but other than that, I don't know if there is any difference.

      Ok. I think that this is a server side problem that you can fix. It would be nice to fix it because it means that you can hide the location of your FLV files... and if we can get this working, then it will restore my sense or order in the universe.

      I ran two tests. I requested an FLV file exactly as it would be requested by your Flash player. These were the headers that I received when I requested the FLV file itself.

      HTTP request sent, awaiting response... 
        HTTP/1.1 200 OK
        Date: Tue, 24 Jul 2007 22:35:15 GMT
        Server: Apache/2.0.46 (Red Hat)
        Last-Modified: Thu, 14 Dec 2006 18:02:57 GMT
        ETag: "80c0e8-5e01c4-533b5640"
        Accept-Ranges: bytes
        Content-Length: 6160836
        Connection: close
        Content-Type: text/plain; charset=ISO-8859-1
      Length: 6,160,836 (5.9M) [text/plain]
      

      Then I wrote a PHP script that looks like this:

      <?php
      header('Content-Type: video/x-flv');
      readfile("ver2.flv");
      ?>
      

      which is exactly the way you were serving the file with your PHP script. These are the headers that were returned when I requested the flv file by running it through the PHP script:

        HTTP/1.1 200 OK
        Date: Tue, 24 Jul 2007 22:41:24 GMT
        Server: Apache/2.0.46 (Red Hat)
        X-Powered-By: PHP/4.3.11
        Connection: close
        Content-Type: video/x-flv
      Length: unspecified [video/x-flv]
      

      As you can see, they are significantly different. I think that if you change your headers, you can get this to work through the PHP script.

        Hi, etully,

        Thanks a lot for looking into this further. I tried using the text/plain header again - which is what I think you are asking me to try - but it didn't solve the problem.

        My assumption was that when testing the PHP script in a browser, I should have seen a message like "what do you want to do with this Flash Video File?" instead of the "What do you want to do with this PHP file?" Is that what I should expect to see?

        I would love to figure this out because, as it stands now, I have no idea how else I can secure the FLV file locations from unauthorized download. As I mentioned before, I can get it to work somewhat by using the Video object instead of the FLVPlayback component in Flash, but it still doesn't progressively load into the Flash which is what needs to happen for usability purposes.

        Any other ideas? In lieu of solving the PHP/Flash problem, what else could I do to prevent the FLV files from being downloaded by unregistered users?

        Sorry to add more chaos to your universe... :queasy:

        Joe

          I tried using the text/plain header again - which is what I think you are asking me to try

          No... There are other significant differences between the two headers. In addition to the text/plain content type, these also appear when you call a true FLV file:

          ETag: "80c0e8-5e01c4-533b5640"
          Accept-Ranges: bytes
          Content-Length: 6160836
          Content-Type: text/plain; charset=ISO-8859-1
          Length: 6,160,836 (5.9M) [text/plain]
          

          You should use the header command to generate those... and it should work.

          It should work because once you make the headers the same - then the two downloads will be precisely the same. Exactly precisely the same. When they are the same, the client can't possibly know whether the source was a true FLV file or a PHP script handing out a PHP file.

            Hi, etully,

            I tried using all the headers you specified - plus a set from my own "get headers" experiments - all without success: the FLVPlayback still won't load an FLV served up with my PHP script.

            Any other ideas?

            Thanks,

            Joe

              Hi, etully,

              I just installed and tried wget in the way you suggested.

              I noticed that a wget for resource.php reports the correct MIME type, but is definitely not retrieving the actual FLV file because the Length is reported as 262, whereas the test.flv Length is 5,967,743.

              wget for test.flv

              HTTP/1.1 200 OK
              Date: Wed, 25 Jul 2007 18:58:50 GMT
              Server: Apache/2.0.55 (Win32) PHP/4.4.6
              Last-Modified: Wed, 27 Jun 2007 02:09:29 GMT
              ETag: "7648-5b0f7f-bc76e8c3"
              Accept-Ranges: bytes
              Content-Length: 5967743
              Keep-Alive: timeout=15, max=100
              Connection: Keep-Alive
              Content-Type: video/x-flv
              Length: 5,967,743 (5.7M) [video/x-flv]

              wget for resource.php

              HTTP/1.1 200 OK
              Date: Wed, 25 Jul 2007 18:59:07 GMT
              Server: Apache/2.0.55 (Win32) PHP/4.4.6
              X-Powered-By: PHP/4.4.6
              Content-Length: 262
              Keep-Alive: timeout=15, max=100
              Connection: Keep-Alive
              Content-Type: video/x-flv
              Length: 262 [video/x-flv]

              Anyway, in my PHP script I set every header returned by the wget request for the the test.flv file.

              header('Date: Wed, 25 Jul 2007 18:58:50 GMT');
              header('Server: Apache/2.0.55 (Win32) PHP/4.4.6');
              header('Last-Modified: Wed, 27 Jun 2007 02:09:29 GMT');
              header('ETag: "7648-5b0f7f-bc76e8c3"');
              header('Accept-Ranges: bytes');
              header('Content-Length: 5967743');
              header('Keep-Alive: timeout=15, max=100');
              header('Connection: Keep-Alive');
              header('Content-Type: video/x-flv');
              header('Length: 5,967,743 (5.7M) [video/x-flv]');
              readfile("resources\test.flv");

              But it still doesn't work. Any other ideas?

              J

                Ok. This is my last suggestion. It's based on the fact that the output size was only 262. I'm going to guess that readfile() isn't doing what it's supposed to be doing. (Maybe that was the problem all along?)

                Replace the readfile command with this:

                    $filename = "test.flv";
                    $fd = fopen($filename, "r");
                    while(!feof($fd)) {
                         echo fread($fd, 4096);
                        flush();
                    }
                    fclose ($fd);
                

                You may need to try a few different values instead of the 4096. If the 4096 doesn't work, try a million - or even 6 million. I'm not too clear on what effect that has. You might even try replacing it with filesize($filename)

                When you try this, point wget at the resource.php script and see if you can get that Length: to reflect the correct size of the FLV file. If that doesn't work let me know and I'll run the test on my server. If it works on my Linux server, then I'm going to have to ask you to abandon your Windows server. 🙂

                  etully, I think we may be getting somewhere with this... I tried the code you supplied, tinkered with it slightly after some trial and error, and ended up with:

                  $filename = "resources/test.flv";
                  header('Content-Type: video/x-flv');
                  header('Length: ' . filesize($filename));
                  $fd = fopen($filename, "r");
                  while(!feof($fd)) {
                  	echo fread($fd, filesize($filename));
                  	flush();
                  	}
                  fclose ($fd);

                  When I request resource.php with wget, it still downloads a file called "resource.php" but now that file is 5 MB in size (instead of 262 bytes) and I have confirmed that it is, in fact, the original Flash Video file. 🙂 (If I rename it with a .flv extension, it will play in my desktop FLV player.)

                  I suspect that if we can get this PHP script to serve up the FLV with the right file name - or even just with an .flv extension - it ought to load into my FLVPlayback component properly.

                  What do you think?

                  J

                    If you want the file to be saved by the user, add this header :

                    header('Content-Disposition: attachment; filename="file.flv"');

                    (where file.flv is the filename you want to user to see)...

                    Also, if you want to use etully's solution to send a line and then flush it, you should use fgets() that simply read a file line by line, no matter how many bites... see http://www.php.net/fgets

                      pasiphilo wrote:

                      When I request resource.php with wget, it still downloads a file called "resource.php" but now that file is 5 MB in size (instead of 262 bytes)

                      And what happens when you point your Flash player at this PHP script to load the "flv"?

                      pasiphilo wrote:

                      I suspect that if we can get this PHP script to serve up the FLV with the right file name - or even just with an .flv extension - it ought to load into my FLVPlayback component properly.

                      Why do you need to mess with the filename? The flash player just wants to see a stream of bits come down the line - most programs don't care what the file name is because they know that often, they are getting piped through an intermediary just like you're doing now.

                      Try using your Flash player to connect to your server and request the PHP script. It should work.

                        If you want the file to be saved by the user, add this header :

                        I actually need the file to get loaded into my Flash app as opposed to being downloaded by the user. I did try the Content-Disposition header as a means of forcing the correct filename, but that didn't work for the Flash app.

                        And what happens when you point your Flash player at this PHP script to load the "flv"

                        Believe me, that was the very next thing I tried, but that part still doesn't work.

                        Why do you need to mess with the filename? The flash player just wants to see a stream of bits come down the line

                        The FLV isn't actually streaming (since I'm not using a streaming server) but loading progressively into the Flash app. I'm 90% sure that the FLVPlayback component will not load anything without a .flv extension whether streamed or not, however.

                        Is there no way to serve up the FLV from PHP with the correct file extension?

                          Is there no way to serve up the FLV from PHP with the correct file extension?

                          You sir, are in luck. As mentioned earlier in this very thread, you can have FLV files parsed for PHP.

                          Do this:

                          1. create a directory called resources (you've already done that)
                          2. put the FLV in there but change the extension to something like XXX or whatever
                          3. put the PHP serving file in the resources directory too
                          4. change the extension of the PHP file to FLV
                          5. create a file called .htaccess (note the dot at the beginning of the name)
                          6. The entire contents of the file are:
                            AddType application/x-httpd-php .flv
                          7. put the .htaccess file inside the resources directory
                          8. double check the PHP script to make sure that it includes the FLV file by the new name (.xxx)
                          9. point your Flash player at the PHP script that has the new FLV extension

                          This will solve your problem IF you are correct that the Flash player is determined to get the file with an FLV extension.

                          By the way, this is just one way to make your web server serve up a file with a different name than what the user thinks they're asking for. There is another way called a rewrite rule but for this situation, I think the .htaccess solution is more elegant.

                            etully... IT WORKS! 😃

                            That extension switcheroo trick cinched it. You are awesome!

                            Here is the working solution, consolidated into one post for anyone else who ever has this problem...

                            The files in the "resources/" folder:

                            resources/
                            -- .htaccess
                            -- test.xxx (a renamed FLV file)
                            -- resource.flv (a renamed PHP script)

                            The .htaccess file:

                            AddType application/x-httpd-php .flv

                            The PHP script (renamed to "resource.flv"):

                            $filename = "test.xxx";
                            header('Content-Type: video/x-flv');
                            header('Length: ' . filesize($filename));
                            header('Content-Disposition: attachment; filename="'.$filename.'"');
                            $fd = fopen($filename, "r");
                            while(!feof($fd)) {
                            	echo fread($fd, filesize($filename));
                            	flush();
                            	}
                            fclose ($fd);

                            The salient ActionScript:

                            //my FLVPlayback compontent instance is named "video"
                            video.load("http://www.myserver.com/resources/resource.flv");

                            That should cover it.

                            Thanks again for all your help! I hereby promote you to "Señor" Curmudgeon. 😉

                            J

                              Cool!!

                              I'm a little disappointed in Flash that it needs the FLV extension. Maybe it's just the player you are using but if it's a requirement of Flash, they should know that people often have reasons to name files something other than .flv (your situation is a textbook example).

                              Note, for your own edification, that by putting the .htaccess file in the resources directory, you are telling your web server that you only want FLV's parsed for PHP when they are inside this directory. You could have put the .htaccess file one directory up (in your root) but then every FLV file that you ever put on your web site would be parsed for PHP which would slow your web server down because you're forcing it to look for PHP code in files where none exists.

                              Also be aware that now that we know the cause of the problem it's possible that you could use the readfile() command instead of the fopen code. It's also possible that the Content-Type doesn't actually need to be "video/x-flv". I understand that you have the system working and don't want to break it but do realize that those parts might not be strictly necessary.

                              I hereby promote you to "Señor" Curmudgeon

                              One of our experts here (Weedpacket) used Señor Curmudgeon and my title is a little nod to his wisdom and experience. Thank you for the vote of confidence but I will remain Juñor for quite some time.

                                I'm a little disappointed in Flash that it needs the FLV extension.

                                This is the error I was getting from Flash before trying the file extension trick, when it thought it was getting a .php file:

                                1005: Invalid xml: URL: "http://www.myserver.com/resource.php" No root node found; 
                                if file is an flv it must have .flv extension

                                Your warnings about the .htaccess file and the extraneous headers are well heeded; I'll be fine tuning further as I integrate this solution into the final application.

                                Thanks again,

                                J

                                  Hi, etully,

                                  I just hit a (hopefully minor) snag, something I should have accounted for before now: My full-blown app needs to send an id in the querystring to the resource.flv, like so:

                                  resource.php?id=12345

                                  I'm finding that when calling resource.flv (PHP) from the Flash like above, the querystring gets appended to the filename extension returned, so instead of feeding "resource.flv" into the Flash, the script returns "resource.flv@id=12345" instead, meaning it no longer has that much-needed .flv file extension. (Flash seems to interpret ".flv@id=12345" as the whole file extension, in other words.)

                                  You mentioned a "rewrite rule" a couple of posts back that might serve as an alternative for rewriting the file name. Could we try that?

                                    Add this to the bottom of your .htaccess file:

                                    RewriteEngine on
                                    RewriteCond %{REQUEST_URI} .*translate.*
                                    RewriteRule .*translate-(.*)\.flv resource.flv?$1
                                    

                                    Now, when you call your FLV file, give it a name like this:

                                    translate-id=12345.flv
                                    

                                    This way, Flash is requesting "X" and when the web server hears the request, it looks for "Y" instead and sends the data back to Flash.

                                    The PHP script thinks that the user actually requested "resource.flv?id=12345" but Flash thinks that it asked for translate-id=12345.flv

                                    The rewrite rule looks for TRANSLATE - (something) . FLV

                                    and converts it to: RESOURCE.FLV?(somthing)

                                    So whatever the "something" is gets tacked onto the end after the question mark.

                                    The only caveat is that you can no longer use any files in the resources directory with the word "translate" in their title because when you try to call them they would get converted!

                                      It's kind of bad form to use re-write rules and "AddType application/x-httpd-php" at the same time. That can make for a real headache when someone else has to figure out what you did when you are no longer involved with the project.

                                      The "correct" way to handle this should be to take out the "AddType" directive in .htaccess and make the rewrite condition change the name from translate-id=12345.flv to resource.php?x=12345

                                      (and change the name of resource.flv back to resource.php of course. And change the name of test.xxx back to test.flv. And change the PHP script so that it's once again calling an FLV file instead of an XXX file.)

                                      Everything should work fine if you don't make these changes... but you always need to consider that if you get hit by a bus, someone else is going to have to figure out what kind of crazy maze you built.