HTML5 video stream only to player - php

I am trying to make my videos on website harder to download, but failed with one point. Solution works good if your goal is to kill video link after 15 mins (enough for user to see video).
But also i want let player get this streaming into HTML5 video player, but don't let user to download it by putting video source link in new tab.
I tried to made this link one-time-working, but the problem is that HTML5 player connects to streaming script more than one time.
So probably there is any solution how in my streaming script i can check if script forced to open directly or forced by HTML5 player? Or maybe there is another way how to block direct opening of this script?
Streaming script:
<?php
[...]
if (!empty($_GET['id']) && !empty($_GET['token'])){
if (strtotime($array['created']) > strtotime('-15 minutes')) {
$file = 'Z:/home/localhost/www/mvc/video/' . $_GET['id'];
$fp = #fopen($file, 'rb');
$size = filesize($file); // File size
$length = $size; // Content length
$start = 0; // Start byte
$end = $size - 1; // End byte
header('Content-type: video/mp4');
//header("Accept-Ranges: 0-$length");
header("Accept-Ranges: bytes");
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $start;
$c_end = $end;
list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (strpos($range, ',') !== false) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
if ($range == '-') {
$c_start = $size - substr($range, 1);
}else{
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
}
$c_end = ($c_end > $end) ? $end : $c_end;
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1;
fseek($fp, $start);
header('HTTP/1.1 206 Partial Content');
}
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: ".$length);
$buffer = 1024 * 32;
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
if ($p + $buffer > $end) {
$buffer = $end - $p + 1;
}
set_time_limit(0);
echo fread($fp, $buffer);
flush();
}
fclose($fp);
exit();
}
else {
echo 'Token is closed';
}
}
else {
echo 'Denied';
}
Player looks like this:
<video width="640" height="480" preload controls>
<source src="http://localhost/mvc/video/video.php?id=video.mp4&token=0c9eb340fa59db2accf61b16663c79b1" type="video/mp4">
<source src="movie.ogg" type="video/ogg">
Your browser does not support the video tag.
</video>

Well after two days of cruel fighting i finally found the decision.
To achieve this goal (let HTML5 video player stream video, but block direct download with link), i changed this:
if (!empty($_GET['id']) && !empty($_GET['token'])){
if (strtotime($array['created']) > strtotime('-15 minutes'))
{
stream video...
}
to this:
if (!empty($_GET['id']) && !empty($_GET['token'])){
if (strtotime($array['created']) > strtotime('-15 minutes') && $_SERVER['HTTP_RANGE'] == true) {
stream...
}
Sure this is not 100% guarantee to protect your video, but now it is harder to download.

Related

How to open video/mp4 with php

I'm trying to read mp4 files with PHP, my initial code was
$file = 'https://s3-sa-east-1.amazonaws.com/onlytestes/video.mp4';
header('Content-type: video/mp4');
readfile($file);
But that way I couldn't use the length bar of the video, skip or even go back, until the video is 100% loaded.
Of course when I read the file directly (video.mp4) everything is fine.
I solved this problem with the following code:
$request = 'video.mp4';
$file = $request;
$fp = #fopen($file, 'rb');
$size = filesize($file); // File size
$length = $size; // Content length
$start = 0; // Start byte
$end = $size - 1; // End byte
header('Content-type: video/mp4');
header("Accept-Ranges: 0-$length");
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $start;
$c_end = $end;
list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (strpos($range, ',') !== false) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
if ($range == '-') {
$c_start = $size - substr($range, 1);
}else{
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
}
$c_end = ($c_end > $end) ? $end : $c_end;
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1;
fseek($fp, $start);
header('HTTP/1.1 206 Partial Content');
}
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: ".$length);
$buffer = 1024 * 8;
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
if ($p + $buffer > $end) {
$buffer = $end - $p + 1;
}
set_time_limit(0);
echo fread($fp, $buffer);
flush();
}
fclose($fp);
exit();
But it only works with local files, I think HTTP_RANGE does not work, it returns the following error in the console
''Failed to load resource: the server responded with a status of 416 (Requested Range Not Satisfiable)''
I need to read Amazon S3 videos, for example: video here
Does anyone have any ideas?
Have you read Document Manual Amazon SDK..?
(1) Download latest stable version of SDK
(2) Extract the .zip file & place in wamp/www folder
(3) Rename config-sample.inc.php file to config.inc.php
(4) Add the access key & secret key (retrieved from Amazon S3 account) into
above file, save & exit
(5) create a sample file to display public / private objects from Amazon S3
thank you Yusnur Hidayah
But I still have problems,
Opening the file by the SDK / StreamWrapper, it takes about 18 seconds for the video to start, see
http://192.241.159.176/file.php
This way it is impossible to make available to users
Usually opens in 1 or 2 seconds, see
https://s3-sa-east-1.amazonaws.com/onlytestes/video.mp4

Stream mp4 video in php file with speed limitation

I want to open a video/mp4 file in a php file to use it in the player. I want to limit the file upload speed to 100 kb/s.
<?php
$file = 'video.mp4';
$fp = #fopen($file, 'rb');
$size = filesize($file); // File size
$length = $size; // Content length
$start = 0; // Start byte
$end = $size - 1; // End byte
header('Content-type: video/mp4');
header("Accept-Ranges: 0-$length");
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $start;
$c_end = $end;
list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (strpos($range, ',') !== false) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
if ($range == '-') {
$c_start = $size - substr($range, 1);
}else{
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
}
$c_end = ($c_end > $end) ? $end : $c_end;
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1;
fseek($fp, $start);
header('HTTP/1.1 206 Partial Content');
}
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: ".$length);
$buffer = 1024 * 8;
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
if ($p + $buffer > $end) {
$buffer = $end - $p + 1;
}
set_time_limit(0);
echo fread($fp, $buffer);
flush();
}
fclose($fp);
exit();
?>
And it works fine, how to limit the speed of loading a file? And what are the optimal settings (so that the video loads smoothly, at a speed without jamming)
I have a page as a file server, it contains video files that I want to give you the opportunity to play. To maintain the server I want to force users to buy premium accounts to speed up video encoding

How to make live streaming using php?

I have live-streaming link where its format extension is .m3u8.
and I want it to be live in to my page.
I tried this code but it does'nt work
<?php
$file = 'http://93.87.85.70/PLTV/88888888/224/3221226661/04.m3u8';
$fp = #fopen($file, 'rb');
$size = filesize($file); // File size
$length = $size; // Content length
$start = 0; // Start byte
$end = $size - 1; // End byte
header('Content-type: video/mp4');
//header("Accept-Ranges: 0-$length");
header("Accept-Ranges: bytes");
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $start;
$c_end = $end;
list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (strpos($range, ',') !== false) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
if ($range == '-') {
$c_start = $size - substr($range, 1);
}else{
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
}
$c_end = ($c_end > $end) ? $end : $c_end;
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1;
fseek($fp, $start);
header('HTTP/1.1 206 Partial Content');
}
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: ".$length);
$buffer = 1024 * 8;
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
if ($p + $buffer > $end) {
$buffer = $end - $p + 1;
}
set_time_limit(0);
echo fread($fp, $buffer);
flush();
}
fclose($fp);
exit();
?>
Is there something wrong or I am needed to add something there?
Or if this code is wrong what another method am gonna use.
.m3u8 is a playlist file, not an MP4 video. It's commonly used with HLS streams.
An HLS stream is made up of a whole collection of files. There will be audio/video file segments every several seconds, possibly at several bitrates, with the playlist. The playlist is updated regularly.
Even if you did want to proxy these files, your script is not the way to do it. Best to leave it up to the web server (Nginx, Apache, whatever you're using), as that's what it does best. Your script isn't respecting the upstream content type, headers, etc. It's also ignoring any errors on fopen(). I wouldn't use fopen() on a URL anyway... the wrappers aren't always enabled, and then you don't have access to the real status codes and headers. And finally, you've hardcoded the upstream path so your users would only get the playlist and not the media files.
All you have to do is use a client-side player than handles HLS, like JWPlayer or similar. This has nothing to do with PHP. It's done with JavaScript and the Media Source Extensions API.

PHP Stream to html5 Video, Page Navigation not working

i have troubles with Streaming .mp4 Videos from PHP to a HTML5 Video Tag. The Video Streams fine and also moving forward and backward works. BUT: If i click on any Link in my Menu, the Site will not change. The loading Icon Appears on the Tab and the Dev Tools show that there is a request. But the request "waits" until the Video Stream End. So if the Video ended, the new Page will load, but not before.
Any ideas on this?
PS: Adding session_write_close(); before streaming the File solves the Problem. But it looks a bit too hacky for me...
<video style="width:100%;" preload="metadata" controls="">
<source src="/uploads/getfile?image_path=5%2FOKzAAFlSub-VLsnFWvkPWXBLluwOV-Q5DIuqJkPpDubahlAosK.mp4&type=20" type="video/mp4">
Your browser does not support the video tag.
</video>
PHP Code:
$file = Yii::getAlias('#app') . '/../files/uploads/' .$image_path;
$fp = #fopen($file, 'rb');
$size = filesize($file); // File size
$length = $size; // Content length
$start = 0; // Start byte
$end = $size - 1; // End byte
header('Content-type: video/mp4');
header("Accept-Ranges: 0-$length");
header("Accept-Ranges: bytes");
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $start;
$c_end = $end;
list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (strpos($range, ',') !== false) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
if ($range == '-') {
$c_start = $size - substr($range, 1);
}else{
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
}
$c_end = ($c_end > $end) ? $end : $c_end;
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1;
fseek($fp, $start);
header('HTTP/1.1 206 Partial Content');
}
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: ".$length);
$buffer = 1024 * 8;
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
if ($p + $buffer > $end) {
$buffer = $end - $p + 1;
}
set_time_limit(0);
echo fread($fp, $buffer);
ob_flush();
}
fclose($fp);
exit();
Adding session_write_close(); before streaming the File solves the Problem. But it looks a bit too hacky for me...
There isn’t much “hacky” about this.
A long-running script that keeps a session open will block access to that same session for all other scripts that get started later on (as with your menu link click.)
To avoid that, you close the session in the long-running script as soon as you are done with it, so that the lock on the session data file can be released.
What is quite “hacky” though, is streaming video data via a script in the first place. That is what you should avoid doing in the first place, if at all possible. It is not a good idea in terms of memory usage and script runtimes.
It is better to use already exist PHP package to support partial download. Here is one of them from pear:
http://pear.php.net/manual/en/package.http.http-download.php
It support several types of download (partial, stream , ..). Here is a sample code:
$dl = &new HTTP_Download();
$dl->setData($data);
$dl->setLastModified($unix_timestamp);
$dl->setContentType('application/x-gzip');
$dl->setContentDisposition(HTTP_DOWNLOAD_ATTACHMENT, 'latest.tgz');
$dl->send();

php serve mp4 instantly (before loading everything)

I'm implementing a HTML5 video player that serves mp4-files.
When I use a regular mp4 file as a source, the video starts pretty soon and I can also seek to parts that aren't downloaded yet.
Now, I want to secure my video files, i.e. they are stored below the web root and the video src is a php-file, that checks, if the user is allowed to view the video.
So my HTML looks like this:
...
<video src="http://videoserver.com/stream.php?file=videoxy.mp4">
...
And the stream.php:
...
if ($access_granted) {
if ($fd = fopen($path, "rb")) {
$fsize = filesize($path);
header("Content-Type: video/mp4");
header("Content-Disposition: inline; filename=\"".$filename."\"");
header('Content-Transfer-Encoding: binary');
header("Content-Length: $fsize");
fpassthru($fd);
} else {
die('file not found');
}
} else {
die('forbidden');
}
...
Now, the video will still be played, but only after the video is completely downloaded.
How can I make the video start before everything is downloaded? Also I'd like seeking to not yet downloaded parts to work as before.
I found the solution from this gist to be working:
...
if ($access_granted) {
if ($fp = fopen($path, "rb")) {
$size = filesize($path);
$length = $size;
$start = 0;
$end = $size - 1;
header('Content-type: video/mp4');
header("Accept-Ranges: 0-$length");
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $start;
$c_end = $end;
list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (strpos($range, ',') !== false) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
if ($range == '-') {
$c_start = $size - substr($range, 1);
} else {
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
}
$c_end = ($c_end > $end) ? $end : $c_end;
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1;
fseek($fp, $start);
header('HTTP/1.1 206 Partial Content');
}
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: ".$length);
$buffer = 1024 * 8;
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
if ($p + $buffer > $end) {
$buffer = $end - $p + 1;
}
set_time_limit(0);
echo fread($fp, $buffer);
flush();
}
fclose($fp);
exit();
} else {
die('file not found');
}
} else {
die('forbidden');
}
...

Categories