PHP Remote Streaming Not Working On iOS (Safari, Chrome) - php

I found this code laying around on the web some time ago to stream remote video files through my server and it works perfectly except on iOS (iPhone 6S, iOS 12.4). Went to tons of threads that recommended having the 'Accept-Ranges', 'Content-Length' and the 'Content-Type' headers, which are already implemented in the code. iOS is refusing to stream the file, both on Safari and Chrome.
Any help would be greatly appreciated!
EDIT #1
Apparently my server is not returning ranges correctly. Apple usually asks first for partial content like "Range: bytes=0-1". Currently it's stuck waiting for a response from the code. Also verified that it isn't working on Safari for macOS. Oh Apple.
ini_set('max_execution_time', 0);
$useragent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36";
$v = 'https://notmywebsite/remotevideo.mp4';
$ch = curl_init();
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 222222);
curl_setopt($ch, CURLOPT_URL, $v);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$info = curl_exec($ch);
$size2 = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
$filesize = $size2;
$offset = 0;
$length = $filesize;
header("Content-Type: video/mp4");
if (isset($_SERVER['HTTP_RANGE'])) {
$partialContent = "true";
preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$offset = intval($matches[1]);
$length = $size2 - $offset - 1;
} else {
$partialContent = "false";
}
if ($partialContent == "true") {
header('HTTP/1.1 206 Partial Content');
header('Accept-Ranges: bytes');
header('Content-Range: bytes '. $offset .
'-' . ($offset + $length) .
'/'. $filesize);
} else {
header('Accept-Ranges: bytes');
}
header("Content-length: ". $size2);
if (isset($_SERVER['HTTP_RANGE'])) {
// if the HTTP_RANGE header is set we're dealing with partial content
$partialContent = true;
// find the requested range
// this might be too simplistic, apparently the client can request
// multiple ranges, which can become pretty complex, so ignore it for now
preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$offset = intval($matches[1]);
$length = $filesize - $offset - 1;
$headers = array(
'Range: bytes=' . $offset .
'-' . ($offset + $length) .
''
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 222222);
curl_setopt($ch, CURLOPT_URL, $v);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
curl_setopt($ch, CURLOPT_NOBODY, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
curl_exec($ch);

I did find a solution. The code above was very messy so I cleaned it up a bit. It now works on macOS and iOS!
<?php
header('Content-Type: video/mp4');
header('Accept-Ranges: bytes');
$agent = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36';
$url = 'https://notmywebsite/remotevideo.mp4';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_USERAGENT, $agent);
curl_setopt($ch, CURLOPT_REFERER, $url); //Remote video might need it to get proper response
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
$info = curl_exec($ch);
$filesize = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
$end = $filesize - 1;
if (isset($_SERVER['HTTP_RANGE'])) {
//If ranges are requested, perform a reg match and extract them
preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$fr = intval($matches[1]);
$sr = is_null($matches[2]) ? $end : intval($matches[2]);
$headers = array("Range: $matches[0]");
header('HTTP/1.1 206 Partial Content');
header("Content-Range: bytes {$fr}-{$sr}/{$filesize}");
//Here we set the headers (ranges) for the remote video request
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_NOBODY, false);
curl_exec($ch);
curl_close($ch);
exit;
?>

Related

Can I let fsockopen go through a proxy without awareness?

The php code is like:
<?php
$fp = fsockopen("www.google.com",80);
fputs($fp, "GET / HTTP/1.0\r\n\r\n");
$data="";
while (!feof($fp)) $data.=fgets($fp,64000);
fclose($fp);
I know I can change the code to use a proxy like:
<?php
$fp = fsockopen("exampleproxy.com",3128);
fputs($fp, "GET http://www.google.com HTTP/1.0\r\n\r\n");
$data="";
while (!feof($fp)) $data.=fgets($fp,64000);
fclose($fp);
But can I configure a system-wide proxy to let all the internet traffic go through that proxy so that I do not need to change the code? I am on Centos 7.
You haven't to use fsock, curl can be easy way rather fsock.
https://www.php.net/manual/en/function.curl-setopt.php
<?php
$url = 'https://google.com';
$proxyauth = 'user:pass';
$proxy = '1.2.3.4';
$proxyPort = '443';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
//proxy suport
curl_setopt($ch, CURLOPT_PROXY, $proxy);
curl_setopt($ch, CURLOPT_PROXYPORT, $proxyPort);
//curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyauth);
curl_setopt($ch, CURLOPT_PROXYTYPE, 'HTTP');
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
//https
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/27.0.1453.94 Safari/537.36");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
$output = curl_exec($ch);
if(curl_exec($ch) === false)
{
echo 'Curl error: ' . curl_error($ch);
}
else
{
echo 'Operation completed without any errors';
}
echo $output;
curl_close($ch);
?>

PHP stream remote video file

Let's say I have a video on a remote server and this its url
"http://domain/video-path/video.mp4"
What is the correct way to stream this video using php with seekable..
I know how to stream the video using fopen and fread but it can't seek with remote file
I'm using this, working both local & external video, seekable & resumable
ini_set('max_execution_time', 0);
$useragent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36";
$v = $_GET['url'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 222222);
curl_setopt($ch, CURLOPT_URL, $v);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$info = curl_exec($ch);
$size2 = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
header("Content-Type: video/mp4");
$filesize = $size2;
$offset = 0;
$length = $filesize;
if (isset($_SERVER['HTTP_RANGE'])) {
$partialContent = "true";
preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$offset = intval($matches[1]);
$length = $size2 - $offset - 1;
} else {
$partialContent = "false";
}
if ($partialContent == "true") {
header('HTTP/1.1 206 Partial Content');
header('Accept-Ranges: bytes');
header('Content-Range: bytes '.$offset.
'-'.($offset + $length).
'/'.$filesize);
header("Content-length: ".$length); // added
} else {
header('Accept-Ranges: bytes');
header("Content-length: ".$size2); // added
}
// header("Content-length: ".$size2); // removed
$ch = curl_init();
if (isset($_SERVER['HTTP_RANGE'])) {
// if the HTTP_RANGE header is set we're dealing with partial content
$partialContent = true;
// find the requested range
// this might be too simplistic, apparently the client can request
// multiple ranges, which can become pretty complex, so ignore it for now
preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$offset = intval($matches[1]);
$length = $filesize - $offset - 1;
$headers = array(
'Range: bytes='.$offset.
'-'.($offset + $length).
''
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 222222);
curl_setopt($ch, CURLOPT_URL, $v);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
curl_setopt($ch, CURLOPT_NOBODY, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
curl_exec($ch);
After the other answers on this hadn't been working for me, I've finally found (after much tweaking) a new solution to this which is working for remote/local files.
<?php
$file = 'https://yourfilelocation';
$head = array_change_key_case(get_headers($file, TRUE));
$size = $head['content-length']; // because filesize() won't work remotely
header('Content-Type: video/mp4');
header('Accept-Ranges: bytes');
header('Content-Disposition: inline');
header('Content-Length:'.$size);
readfile($file);
exit;
?>
This allows tracking etc. too, enjoy!

cUrl can't access to file but browser does

I want to get file contents (without file_get_contents function) via cUrl but I can't open it with cUrl
My link is here
I tested my hosting with requestb.in and results are here
$header = array();
$header[] = 'Accept-Encoding: gzip';
$header[] = 'Connection: close';
$header[] = 'Host: panel.1n3k.com';
$header[] = 'User-Agent: runscope-radar/2.0';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$body = substr($response, $header_size);
curl_close($ch);
I tried with agent CURLOPT_USERAGENT with my browser's agent.
CURLOPT_REFERER, CURLOPT_ENCODING, CURLOPT_AUTOREFERER
one by one but no one could help me...
How this can be posible ?
try this one to view your link image contents
<?php
header("Content-Type: image/jpeg");
$url = 'http://panel.1n3k.com/6512bd43d9caa6e02c990b0a82652dca/api/media/4/logo/831710_1464331440.png';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.1 Safari/537.11');
$res = curl_exec($ch);
$rescode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch) ;
echo $res;
?>

facebook image save curl

The size of the save images 0 kb
Working code, except facebook
function imagedownload($url,$saveto){
$ch = curl_init ($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $args);
$result = parse_url($url);
curl_setopt($ch, CURLOPT_REFERER, $result['scheme'].'://'.$result['host']);
curl_setopt($ch, CURLOPT_USERAGENT,'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0');
$raw=curl_exec($ch);
curl_close ($ch);
if(file_exists($saveto)){
unlink($saveto);
}
$fp = fopen($saveto,'x');
fwrite($fp, $raw);
fclose($fp);
}
$url="http://scontent-frt3-1.xx.fbcdn.net/v/t1.0-0/cp0/e15/q65/p320x320/13700038_850487491753797_6227258625184891703_n.jpg?oh=793ecde8db1a8e65789534907d08b25e&oe=57F1DDFF";
$konum="images/"
$yolla=imagedownload($url,$konum);
The size of the save images 0 kb
Working code, except facebook
It works if you remove the options to POST and do a regular GET request:
<?php
function imagedownload($url, $saveto)
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$result = parse_url($url);
curl_setopt($ch, CURLOPT_REFERER, $result['scheme'] . '://' . $result['host']);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0');
$raw = curl_exec($ch);
curl_close($ch);
if (file_exists($saveto)) {
unlink($saveto);
}
$fp = fopen($saveto, 'x');
fwrite($fp, $raw);
fclose($fp);
}
$url = "http://scontent-frt3-1.xx.fbcdn.net/v/t1.0-0/cp0/e15/q65/p320x320/13700038_850487491753797_6227258625184891703_n.jpg?oh=793ecde8db1a8e65789534907d08b25e&oe=57F1DDFF";
$konum = "test.jpg";
$yolla = imagedownload($url, $konum);
I had try in my localhost this code and it working well.
<?php
ini_set('display_errors', 1);
function imagedownload($url,$saveto){
$ch = curl_init ($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
$raw=curl_exec($ch);
curl_close ($ch);
if(file_exists($saveto)){
unlink($saveto);
}
$fp = fopen($saveto,'x');
fwrite($fp, $raw);
fclose($fp);
}
$url="http://scontent-frt3-1.xx.fbcdn.net/v/t1.0-0/cp0/e15/q65/p320x320/13700038_850487491753797_6227258625184891703_n.jpg?oh=793ecde8db1a8e65789534907d08b25e&oe=57F1DDFF";
$konum="/var/www/html/jsPDF-master/examples/test.jpg";
$yolla=imagedownload($url,$konum);
?>
And result
And one note: Please make sure the directory for save image must have write permission.
Example: chmod -R 777 /var/www/html/jsPDF-master/examples
Or ensure that in php.ini allow_url_fopen is enable

php get url of redirect from source url

I have this link:
http://libero-news.it.feedsportal.com/c/34068/f/618095/s/2e34796f/l/0L0Sliberoquotidiano0Bit0Cnews0C12735670CI0Esaggi0Eper0Ele0Eriforme0Ecostituzionali0EChiaccherano0Ee0Eascoltano0Bhtml/story01.htm
If you visit it, this become:
http://www.liberoquotidiano.it/news/1273567/I-saggi-per-le-riforme-costituzionali-Chiaccherano-e-ascoltano.html
How can I get the second link from the first?
I have tried this but don't work, returning me the same first link:
<?php
$url="http://libero-news.it.feedsportal.com/c/34068/f/618095/s/2e34796f/l/0L0Sliberoquotidiano0Bit0Cnews0C12735670CI0Esaggi0Eper0Ele0Eriforme0Ecostituzionali0EChiaccherano0Ee0Eascoltano0Bhtml/story01.htm";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$a = curl_exec($ch);
print_r($a);echo"<br>";
if(preg_match('#Location: (.*)#', $a, $r)){
$l = trim($r[1]);
echo $l;
}else echo "not working";
Thanks a lot.
Thanks to #king-isaac the following code was tested and it works.
<?php
$url="http://libero-news.it.feedsportal.com/c/34068/f/618095/s/2e34796f/l/0L0Sliberoquotidiano0Bit0Cnews0C12735670CI0Esaggi0Eper0Ele0Eriforme0Ecostituzionali0EChiaccherano0Ee0Eascoltano0Bhtml/story01.htm";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Must be set to true so that PHP follows any "Location:" header
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$a = curl_exec($ch); // $a will contain all headers
$url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); // This is what you need, it will return you the last effective URL
// Uncomment to see all headers
/*
echo "<pre>";
print_r($a);echo"<br>";
echo "</pre>";
*/
echo $url; // Voila
?>
You can do it without using CURL. Made it simple and short.
<?php
$url="http://libero-news.it.feedsportal.com/c/34068/f/618095/s/2e34796f/l/0L0Sliberoquotidiano0Bit0Cnews0C12735670CI0Esaggi0Eper0Ele0Eriforme0Ecostituzionali0EChiaccherano0Ee0Eascoltano0Bhtml/story01.htm";
$headers = #get_headers($url);
$final_url = "";
foreach ($headers as $h)
{
if (substr($h,0,10) == 'Location: ')
{
$final_url = trim(substr($h,10));
break;
}
}
echo $final_url;
?>
You can get the final URL of a request with curl_getinfo.
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_exec($ch);
$url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
If you want to get first redirect:
function getRedirect($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36');
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$responseHeaders = curl_exec($ch);
curl_close($ch);
if(preg_match_all("/^location: (.*?)$/im", $responseHeaders, $results))
return $results[1][0];
}

Categories