I have a php page with an embedded HTML5 video, say video.mp4. On cloudflare, I have a pagerule setup for mydomain.com/.php* and set it to cache everything. Will cloudflare cache the embedded video?
Thanks.
EDIT: Apparently cloudflare f***s up when caching videos. If a user watches half a video and cloudflare only caches that, every single visitor to your website will receive half the video.
But where do you want it to cache? In memory on the cloudflare server, or the user's Browser. I assume the latter because the former should not matter
have you tried:
preload="auto"
Check the HTTP Response Header to see if it has
Cache-Control: max-age=xxxxx
Where xxxxx = number of seconds the Browser should cache.
'Expires' is also a date where the Browser would no longer keep it in cache.
To see the Header, right click, select Inspect Element, go to the "Network Tab" refresh the page, select the video from the list of resources, view the Response Header.
To store the video in memory, the PHP /tmp directory is a memory directory.
To verify the tmp directory use:
echo sys_get_temp_dir();
To get the video into the temp directory
$data = file_get_contents('http://example.com/video/test.mp4');
$fp = fopen('/tmp/test.mp4','w');
fwrite($fp,$data);
fclose($fp);
You may need to set a handler for content-type: video/mp4.
But the type on the video control should do it. As I recall I had to set the handler, so the HTTP response header had the correct content type.
<source src="/tmp/test.mp4" type="video/mp4";/>
You could make a PHP script to server the mp4 with the correct header.
header('Content-Type: video/mp4');
echo file_get_contents('/tmp/test.mp4');
Then in the video control:
src="video.php"
How come you don't have the PageRule set to mydomain.com/* to cache everything?
"Will cloudflare cache the embedded video?"
But, yes, the PageRule should cache everything.
Related
I have a big problem. I have a video streamer site. The site has public and private videos, private videos can be seen after purchase.
Here you can see the directory structure:
/public_html
|__/vendor
|__/src
|__/public
|__/product
|__/sample-video
|__/video.mp4
Well, as you can see the videos are located outside the public folder. The goal is to make them inaccessible directly.
Here is the twig:
<video id="myVideo">
<source src="/products/12?video=10&cache={{ random(50, 10000) }}" type="video/webm" />
<source src="/products/12?video=10&cache={{ random(50, 10000) }}" type="video/mp4" />
</video>
The video controller:
https://pastebin.com/sne1mSHH
And the video stream logic:
https://pastebin.com/2Sxd7Nqq
Here's the problem:
I'm going to the site. You switch between pages. Perfectly good. I go to a page with a video still good and after I start the video, the page is not good.. The page just loads and does nothing. I can't switch between pages anymore. I have to close the incognito mode and start a new session.
Until now I thought that the session lock was the problem, but I close the write session.
I tried opening the video in a new tab. Also the error is until the video stream is finished, the page does not handle the request.
So while the video is playing, while I can't send a new request.
What else can I attach to make the error more transparent?
Help pls!
I would personnally not use PHP to stream the video. The problem is that you'll have to many PHP processes locked for reading and streaming a big file instead of handling logic. You will also have a PHP timeout during this process.
Instead, I would use the Sendfile module:
You install an Apache module or other kind of Sendfile module for your web server, NGINX or whatever.
In PHP, you do the logic for the protection and just send a HTTP header to say you want Sendfile to handle the streaming. This way your PHP code stops running and its the web server that handles the transmission of the file.
Something like this:
<?php
if (has_access_to_the_video($file))
{
// Send the right HTTP headers.
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Content-type: ' . mime_content_type($file));
header('Content-Length: ' . filesize($file));
// Make sure you have X-Sendfile module installed on your server.
header('X-Sendfile: ' . $file);
exit;
}
else
{
// Generate your 403 error or whatever.
}
This may help you:
https://symfony.com/doc/current/components/http_foundation.html then search for sendfile in the page.
https://github.com/mostafaznv/php-x-sendfile
PHP File Serving using X-Sendfile
https://www.h3xed.com/programming/how-to-use-x-sendfile-with-php-apache
Another remark regarding your video sources
For the <video> tag, you are declaring two <source> elements, one with type="video/webm" and the other with type="video/mp4" but both point to the same URL. In your PHP logic, I don't see any handling of the desired content type so your server is probably returning the same video file for both codecs and this is problematic. I would add the video content type in the URL and on the server side, do the internal redirection with Sendfile to the correct file (MP4, OGG, WEBM, etc). If the browser requests a WEBM file and recieves a MP4 H.264 instead, I assume it will not load correctly.
It seems that MP4 H.264 is widely handled by know, so you could just stick with one source. See the current support here:
https://caniuse.com/mpeg4
https://caniuse.com/webm
https://caniuse.com/?search=ogg
I ran into an issue where regardless of the preload attribute setting, when IE9 makes a request for a video, and the video is served by x-sendfile, the request is listed as pending and keeps the connection open.
Consequently, if you have 10 videos trying to load, IE9 will quickly eat up all of its available connections and the browser will not be able to make further requests.
When telling IE9 to request the same video from Apache, without X-Sendfile, Apache serves a small portion of the file as a 200 request. Then the browser makes a request later when the play button is pressed to serve a range of the file.
It looks like X-Sendfile is causing Apache to serve the entire file initially, instead of serving just a part of it.
How can I make X-Sendfile requests via Apache function the same as a regular request to Apache?
Setting the "Accept-Ranges" header like header("Accept-Ranges: bytes"); tells IE9 to attempt to stream the file by default, instead of serve it in one chunk.
It's recommended to check that the HTTP request is version 1.1 though before setting, since 1.0 doesn't support the header.
if (isset($_SERVER['SERVER_PROTOCOL']) && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1') {
header("Accept-Ranges: bytes");
}
I wasn't able to find any documentation on this anywhere, so I'm posting my solution here.
I have a Chromecast and a URL of an mp4 file online. I also have a 2Mbps download connection, which is pathetic and renders direct buffering to the Chromecast too slow. That's what I tried so far:
Through the developer console, I simply set location.href to the online URL of the mp4. The Chromecast would buffer for 20 seconds, play 10 seconds' worth of video, and then buffer again. So, through the console, I paused the video and let it buffer for 5 minutes. When I let it play again, it played for about 15 seconds, and then lost all progress and had to be returned to the home screen.
As I don't want to wait for the whole download of the mp4 to complete, I am currently attempting this: I buffer the mp4 to a local file which is in my htdocs directory, and I then direct the Chromecast to that file's location. However, when opening the mp4 file thorugh Chrome (the browser), instead of playing, it shows a download prompt, and the Chromecast returns to the home screen.
I have implemented the buffering in PHP, and it looks as thus:
$bufferSource = 'http://example.com/path/to/file.mp4';
$bufferedReader = fopen($bufferSource, 'r');
while(!($finished = feof($bufferedReader))){
if($finished !== false){ break; }
//get onle line
$buffer = fgets($bufferedReader);
file_put_contents('buffer.mp4', $buffer, FILE_APPEND);
}
fclose($bufferedReader);
I know that PHP does its work, as I can watch the file size grow on my computer, and I can open the file with VLC. Is there maybe another PHP script I could make to access the locally buffered mp4 file which simulates 'bufferability', so Chrome does not show the download dialog but buffers the file, as should do the Chromecast?
EDIT: One more thing. I am not directing the Chromecast to the PHP script. I am actually directing it directly to the buffer.mp4 file.
You're missing a Content-Type header in your PHP script.
Figure out what the original content type header is from your server (probably video/mp4) and send it with your proxying script like this:
header('Content-Type: video/mp4');
This will allow the browser to detect the content type and play it directly (if supported), without downloading.
Also, I would consider using a real proxy server, such as Nginx, rather than reinventing the wheel. This will be much easier and more reliable.
You can use a receiver with a Media Element tag and then point its source to your mp4 file on your server. If you don't want to write your own receiver, you can use either the default or Styled Media Receiver . You would need a very simple sender to send the url, check out the github repo for examples
I think my question seems pretty casual but bear with me as it gets interesting (at least for me :)).
Consider a PHP page that its purpose is to read a requested file from filesystem and echo it as the response. Now the question is how to enable cache for this page? The thing to point out is that the files can be pretty huge and enabling the cache is to save the client from downloading the same content again and again.
The ideal strategy would be using the "If-None-Match" request header and "ETag" response header in order to implement a reverse proxy cache system. Even though I know this far, I'm not sure if this is possible or what should I return as response in order to implement this technique!
Serving huge or many auxiliary files with PHP is not exactly what it's made for.
Instead, look at X-accel for nginx, X-Sendfile for Lighttpd or mod_xsendfile for Apache.
The initial request gets handled by PHP, but once the download file has been determined it sets a few headers to indicate that the server should handle the file sending, after which the PHP process is freed up to serve something else.
You can then use the web server to configure the caching for you.
Static generated content
If your content is generated from PHP and particularly expensive to create, you could write the output to a local file and apply the above method again.
If you can't write to a local file or don't want to, you can use HTTP response headers to control caching:
Expires: <absolute date in the future>
Cache-Control: public, max-age=<relative time in seconds since request>
This will cause clients to cache the page contents until it expires or when a user forces a page reload (e.g. press F5).
Dynamic generated content
For dynamic content you want the browser to ping you every time, but only send the page contents if there's something new. You can accomplish this by setting a few other response headers:
ETag: <hash of the contents>
Last-Modified: <absolute date of last contents change>
When the browser pings your script again, they will add the following request headers respectively:
If-None-Match: <hash of the contents that you sent last time>
If-Modified-Since: <absolute date of last contents change>
The ETag is mostly used to reduce network traffic as in some cases, to know the contents hash, you first have to calculate it.
The Last-Modified is the easiest to apply if you have local file caches (files have a modification date). A simple condition makes it work:
if (!file_exists('cache.txt') ||
filemtime('cache.txt') > strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
// update cache file and send back contents as usual (+ cache headers)
} else {
header('HTTP/1.0 304 Not modified');
}
If you can't do file caches, you can still use ETag to determine whether the contents have changed meanwhile.
I have an ssl certificate on my web-site. Once images are loaded on the page from another site, it causes warnings kind of "the page contains both secure and nonsecure items", so you have to press OK or you see "broken" ssl connection in the browser. One of the ways to escape that warnings is to use http page instead of https, correct?
But, as far as I know, there is another way to exclude that warnings using php or just using javascript. I believe the images are loaded to the temporary folder on my server and are loaded as https images at the same time.
Could anybody tell me the best way to do that?
Browsing the forum didn't help me a lot.
Thank you.
So,
how to load
<?php echo '<img src="http://www.not_my_site.com/image.jpg" alt="">'; ?>
with no warnings on my page https://my_site.com/index.php ?
You cannot surpress the error as it's a browser thing.
The only way would be to wrap those calls using an https call on your site. Something like:
<?php echo '<a href="https://my_site.com/external.php?resource=http://www.not_my_site.com/image.jpg" alt="">'; ?>
You will have to write the external.php script to make the request on the client's behalf, and then return the content over your existing SSL connection. You only NEED to do this for external HTTP-only resources.
The process would work as follows:
The end user's web browser makes an HTTPS request to your external.php script.
Check for a saved copy of the resource. If you've got it cached then skip to step 6, returning the cached resource.
Your server forwards on the call to the HTTP resource specified as the resource.
The remote server responds to the request.
Save a copy of the resource for caching.
Your web server external.php script then returns that response over the SSL connection.
The web browser only makes 1 request, your web server just has to make an additional one.
This is the only way you'll be able to get rid of the message.
Looks even simpler to retrieve the image: use curl to download indirect image file
It happens cause your making non-secure (HTTP) calls from a secured-page (HTTPS).
try changing your code to:
<?php echo '<a href="https://www.not_my_site.com/image.jpg" alt="">'; ?>