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
Related
In a PHP 7.1 app I load files from a php file "filecache.php" - it works fine in regards of returning a cachable file.
But the thing that drives me crazy is that the images triggers a Insecure content warning in Chrome and FF (perhaps others also).
The files are loaded using a tag, I tried relative url and this gives me the error. I've also tried using complete url https://example.com/filecache?f=0983490842'> same error.
The server uses HSTS and LetsEncrypt cert - no http traffic allowed.
When I examine the Network activity in Chrome (and FF) I can see that the browser tries to retrieve a file using https, finds it in the cache which gives a 307 internal redirect - but to a http url - finally ending up with the image loaded over https from the cache. Well at least thats how I read the info below.
Any input or pointers will be greatly appreciated!
filecache.php
if(file_exists($file)){
if(substr($_GET["f"],-3)=="jpg") Header("Content-Type: image/jpeg");
if(substr($_GET["f"],-3)=="png") header("Content-Type: image/png");
header('Cache-control: max-age='.(60*60*24*365));
header('Expires: '.date("Y-m-d H:i:s",strtotime("+365 days")));
header('Last-Modified: '.gmdate(DATE_RFC1123,filemtime($file)));
readfile($file);
}else{
die("no such file");
}
I have a 4GB .mp4 video I need to allow authenticated users to stream.
I have the video in a directory which is secured via .htaccess like this:
Deny from all
When a user requests access to the video, I use a PHP script to check for authentication, then send the video like this:
<?php
header('Content-Type: video/mp4');
header('Content-Disposition: inline; filename="' . $video . '.mp4"');
header('Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
ob_clean();
$wasdownloaded = readfile('video/' . $video . '.mp4');
if ($wasdownloaded===true){
Flush();
}
?>
I am using Floatbox.js which has built-in (and simple) capability to stream video. I am not tied to using that, though.
I am finding that I can stream 1-3 minutes of the video before it times out, even on a good connection. I would think there are a couple of potential bottlenecks, and not sure where to start:
Is the "readfile" technique in PHP able to handle a 4GB video? It definitely works to start, but possibly it is too much for the server to handle, especially if the video is placed in memory as it is streaming?
Do I need a more sophisticated streaming software platform? Floatbox.js works nicely for small videos or YouTube embeds, but it is not designed primarily for video streaming.
Do I need to look to an outside provider (Vimeo, etc.) to handle streaming, compression, etc.? The issue here is that I don't know if I can authenticate the users as easily, or at all.
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.
My test server is apache 2 to work php coding. i want to create a mp3 server.
Everything is working fine, however today i tried to build an admin page by taking the mp3 info, change it, delete etc. There is a play button in page for selected mp3, when clicked to play button, file loading with header option and playing,
Sample code is here:
session control &
$filename = '/home/bla..bla/mp3/'. $_GET['v'] . '.mp3';
if(file_exists($filename)) {
header('Content-Type: audio/mpeg');
header('Content-length: '.filesize($filename));
header('X-Pad: avoid browser bug');
header('Cache-Control: no-cache');
readfile($filename);
}else{
exit();
}
Everything looks fine, but when i click to another button (e.g. search again mp3 with ajax code or take value with javascript in same page) nothing is happening.
Page is waiting to load mp3 file. looks like blocking request. when mp3 loading %60 or %70, query is coming.
if i can't find a solution,i will be killer :)
ps: my system build on apache2, PHP5 , MySQL, using audio tag in admin page but same problem with jplayer.
Most likely you're running into session locking. When requesting a page in which you session_start(), the session file is opened and locked to prevent problems with concurrent access. The file stays locked until the current script is finished. While the file is locked, other processes can't access it and will wait until it becomes unlocked.
Before you do any long-running tasks like streaming an MP3 file, unlock the session with session_write_close.
Even better, let the web server handle the mundane task of streaming a file, don't keep a PHP process busy with it. Try mod_xsendfile.
I have a PHP script that responds to a GET request for audio resources. An HTML5 Audio tag requests an audio file such as:
<audio src="get_audio.php?f=fun" preload></audio>
There is no need for the user to download that same audio file every time so I would like to cache it. In my PHP file I have:
header("Cache-Control: max-age=2419200");
header("Content-Type: audio/mpeg");
...
echo file_get_contents($path);
but when I view the Network tab of Chrome developer tools I see that it re-downloads the audio clip everytime rather than saying "from cache" and if I look in the Response headers I do see the Cache-Control header that I set. Why would it ignore this? Amidoingitright?
It's been a while since I did this in PHP, but try adding:
header("Pragma: public");
above the cache-control header.
I also think you need the expires header:
header('Expires: ' . gmdate('D, d M Y H:i:s', time()+2419200) . ' GMT');
Other than that you could start using the get_headers() function in PHP to debug where it's going wrong.
Do you see a header in the second request called If-Modified-Since:?
This is what you need to catch, parse and respond to - if you don't want to send the file again, you respond with HTTP/1.1 304 Not Modified. If you are using Apache, you can check for the header in the result of apache_request_headers(). If you are not using Apache, you may find it hard to handle this - you will probably have to find a way for the web server to set the headers as environment variables, so they are available in $_ENV or $_SERVER. There is a way to do this in Apache using mod_rewrite (see latest comment on page linked above), so there is probably a way to do it in other server environments as well.
Caching in HTTP 1.1 permits (and indeed, encourages) this behaviour - it means that the cached copy will always be up-to-date.