How to download client-site a video with cURL / PHP? - php

If the following PHP is runnig, I would like to download the file with `cURL on the client-site. It means, if one of my website visitor run's an action, which starts this PHP file, it should download the file on this PC.
I tried with different locations, but without any success. If I run my code, it does always download it on my WebSever, which is not this, what I want.
<?php
//The resource that we want to download.
$fileUrl = 'https://www.example.com/this-is-a-example-video';
//The path & filename to save to.
$saveTo = 'test.mp4';
//Open file handler.
$fp = fopen($saveTo, 'w+');
//If $fp is FALSE, something went wrong.
if($fp === false){
throw new Exception('Could not open: ' . $saveTo);
}
//Create a cURL handle.
$ch = curl_init($fileUrl);
//Pass our file handle to cURL.
curl_setopt($ch, CURLOPT_FILE, $fp);
//Timeout if the file doesn't download after 20 seconds.
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
//Execute the request.
curl_exec($ch);
//If there was an error, throw an Exception
if(curl_errno($ch)){
throw new Exception(curl_error($ch));
}
//Get the HTTP status code.
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
//Close the cURL handler.
curl_close($ch);
if($statusCode == 200){
echo 'Downloaded!';
} else{
echo "Status Code: " . $statusCode;
}
?>
How can I change the cURL downloading process to the client-site?

PHP cannot run client-side.
You could use cURL to download data to the server (without saving it to a file) and then output that data to the client.
Don't do this:
//Open file handler.
$fp = fopen($saveTo, 'w+');
or this:
//Pass our file handle to cURL.
curl_setopt($ch, CURLOPT_FILE, $fp);
Then capture the output:
//Execute the request.
curl_exec($ch);
Should be:
//Execute the request.
$output = curl_exec($ch);
Then you can:
echo $output;
… but make sure you set the Content-Type and consider setting the Content-Length response headers. You might also want Content-Disposition.
Under most circumstances, it would probably be better to simply send the browser to fetch the file directly instead of proxying it through the server.
$fileUrl = 'https://www.example.com/this-is-a-example-video';
header("Location: $fileUrl");

Related

Trying to get data from a webhook with php json

I'm trying to download a file, which URL I get from a webhook:
<?php
$webhookResponse = json_decode(file_get_contents('php://input'), true);
//The resource that we want to download.
$fileUrl = $webhookResponse["data"]["orderDetails"][0]["detailFiles"][0]["fileUrl"];
//The path & filename to save to.
$saveTo = 'test.pdf';
//Open file handler.
$fp = fopen($saveTo, 'w+');
//If $fp is FALSE, something went wrong.
if($fp === false){
throw new Exception('Could not open: ' . $saveTo);
}
//Create a cURL handle.
$ch = curl_init($fileUrl);
//Pass our file handle to cURL.
curl_setopt($ch, CURLOPT_FILE, $fp);
//Timeout if the file doesn't download after 20 seconds.
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
//Execute the request.
curl_exec($ch);
//If there was an error, throw an Exception
if(curl_errno($ch)){
throw new Exception(curl_error($ch));
}
//Get the HTTP status code.
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
//Close the cURL handler.
curl_close($ch);
//Close the file handler.
fclose($fp);
if($statusCode == 200){
echo 'Downloaded!';
} else{
echo "Status Code: " . $statusCode;
}
?>
When I try to run it, it gives me an error:
Trying to access array offset on value of type null
This is how my array looks that I get from webhook:
Interesting thing, if I put this same script on another server, it works fine, it downloads the file, if I put it one the actual one I need to use (ubuntu, nginx) it gives me this error, could this be a little server related?

How to check whether file completely downloaded using php CURL

I am downloading a recording from an external url and saving it using CURL as follows:
$ch = curl_init($Recording);
$fp = fopen($recording_file_loc, 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
I need to change the file permissions once file is completely downloaded as follows.
chmod($recording_file_loc , 0640);
How can i check and ensure that file is completely downloaded before executing chmod??
updated:
I updated my code as follows:
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
and
if($statusCode == 200){
chmod($recording_file_loc , 0640);
}
else{
echo $statusCode;
}
You need to put to check if the download process is complete.
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progress'); // call progress function
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
Then you need to define a function which checks the download progress
// progress function definition
function progress($resource,$download_size, $downloaded, $upload_size, $uploaded)
{
// Progress
if($download_size > 0)
echo $downloaded / $download_size * 100;
if($downloaded / $download_size == 1){
// chmod code here
}
}
Check this link cURL download progress in PHP
on transfers where curl detected any errors, curl_errno($ch) should no longer return 0, so if(curl_errno($ch)!==0), something bad probably happened to your download.
another thing, as pointed out by #Pamela in a comment, if the response code is not 2XX (like HTTP 200 OK or HTTP 204 No Content), that's another sign something probably went wrong, which can be detected by doing if(((string)curl_getinfo($ch,CURLINFO_RESPONSE_CODE))[0]!=='2')
so..
if(curl_errno($ch)!==0 || ((string)curl_getinfo($ch,CURLINFO_RESPONSE_CODE))[0]!=='2'){
// the download probably failed.
}
generally speaking, this may be impossible to detect on servers that doesn't implement "Content-Length" headers, if you're downloading from a server that doesn't support Content-Length, then there may be no standardized way to detect the broken download at all.. (you may have to inspect what you've downloaded to make sure it's what you expect or something, idk)
for example, on transfers where the body length doesn't match the "Content-Length" header, curl_errno($ch) returns int(56) (instead of the usual int(0)), and curl_exec($ch) returns bool(false) (PS! if you used CURLOPT_RETURNTRANSFER, then it may contain a string instead of bool)
here's a little HTTP server sending "Content-Length: 3", then cutting the connection after just sending 2 (of allegedly 3) bytes of the body:
<?php
$port=1234;
$srv=socket_create_listen($port);
while(($conn=socket_accept($srv))){
$headers=implode("\r\n",array(
"HTTP/1.1 200 OK",
"Content-Type: text/plain",
"Content-Length: 3",
"Connection: close",
"","",
));
// i lied! i said 3 bytes body, but only send 2 bytes body
$body="ab";
$response=$headers.$body;
var_dump(strlen($response),socket_write($conn,$response));
socket_close($conn);
}
and an accompanying test script:
<?php
$ch=curl_init("http://127.0.0.1:1234");
var_dump(curl_exec($ch));
var_dump(curl_errno($ch),curl_error($ch));
printing:
abbool(false)
int(56)
string(38) "Recv failure: Connection reset by peer"
Get the info like this:
$ch = curl_init($Recording);
$fp = fopen($recording_file_loc, 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
fclose($fp);
Then check the "download_content_length" against "size_download" like this:
if($info["download_content_length"]==$info["size_download"])
{
//Download complete!
}
else
{
//Error
}
Note that it works only if server sends the Content-Length header in advance.

Use PHP cURL to download and Excel file

I've been trying for a few days to be able to call a url on a remote server that automatically downloads an Excel file when you put the url into a browser. I made a page locally that automatically downloads the file for testing, but I cannot get cURL to do it. The script returns no errors and says it was successful, but the file it writes to becomes corrupt and opens blank.
Here is the code...
$output_file = 'E:\Downloads\Export.xlsx';
$download_url = 'http://localhost/test/urlexport.php';
$ch = curl_init();
$out = fopen($output_file, 'w');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FILE, $out);
curl_setopt($ch, CURLOPT_URL, $download_url);
$output = curl_exec($ch);
fwrite($out, $output);
if(curl_exec($ch) === false)
{
echo 'Curl error: ' . curl_error($ch);
}
else
{
echo 'Operation completed without any errors';
}
if(curl_errno($ch)){
echo 'Curl error: ' . curl_error($ch);
}
curl_close($ch);
I've spent quite a bit of time researching this but have yet to find an answer that actually works. Any help is appreciated, thanks.
If you're not sure what you're doing - keep it simple.
Here's the simplest possible way to do what you're doing, which is downloading a file and then saving it to disk.
<?php
$output_file = 'E:\Downloads\Export.xlsx';
$download_url = 'http://localhost/test/urlexport.php';
$file = file_get_contents($download_url);
file_put_contents($output_file, $file);
If this doesn't work then your download url isn't doing what you think it's doing. Take a look at what's actually in the $output_file (open it in a text editor) - maybe it's some html.

Php curl get amount of bytes written

How can i know how much data is written in php curl .
Here is my code which downloads i.e writes the data to my local server from a remote url . But i want to know how much data has been written till now .
<?php
$url = 'https://speed.hetzner.de/1GB.bin';
$path = $_SERVER['DOCUMENT_ROOT'] . '/1gb.bin';
$fp = fopen($path, 'w');
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FILE, $fp);
$data = curl_exec($ch);
curl_close($ch);
fclose($fp);
I use this for the downloaded size in bytes (including the size of the file as it is the body of the response) (after you call curl_exec($ch);)
// $ch is the curl handle
$info = curl_getinfo($ch);
echo $info['size_download'];
CURLINFO_SIZE_DOWNLOAD - Total number of bytes downloaded
This is quoted from libcurl documenation
The amount is only for the latest transfer and will be reset again
for each new transfer. This counts actual payload data, what's also
commonly called body. All meta and header data are excluded and will
not be counted in this number.
And this for the size of the request you made with curl in bytes
$info = curl_getinfo($ch);
echo $info['request_size'];
CURLINFO_REQUEST_SIZE - Total size of issued requests, currently only for HTTP requests
you can also use the function with the opt parameter set to one of the function constants, like
echo curl_getinfo($ch, CURLINFO_REQUEST_SIZE);
echo curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD);
getinfo() function
As you told in comments by Dharman, don't switch off CURLOPT_SSL_VERIFYPEER. If you want to use https requests check this php-curl-https

How can I send and receive put query with same script

I need to receive image send by PUT method. So I'm wrinting script for testing it. I want to receive and send it with the same script. How can I implement this? The following variant echoes nothing and string about Congratulations that http method was send ok.
<?php
//if they DID upload a file...
var_dump(file_get_contents("php://input"));
if($_FILES['photo']['tmp_name'])
{
echo $_FILES['photo']['error'];
if($_FILES['photo']['error']==0)
{
//now is the time to modify the future file name and validate the file
$new_file_name = strtolower($_FILES['photo']['tmp_name']); //rename file
$message = 'Congratulations!!!!!!!.';
//move it to where we want it to be
move_uploaded_file($_FILES['photo']['tmp_name'], 'url.../1.jpg');
echo'Congratulations! Your file was accepted.';
$image = fopen('url.../1.jpg', "rb");
var_dump($image);
$ch = curl_init();
/* Set cURL options. */
curl_setopt($ch, CURLOPT_URL, "http://url.../upload.php");
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_INFILE, $image);
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($image));
/* Execute the PUT and clean up */
$result = curl_exec($ch);
fclose($image); //recommended to close the fileshandler after action
curl_close($ch);
}
//if there is an error...
else
{
//set that to be the returned message
$message = 'Ooops! Your upload triggered the following error: '.$_FILES['photo']['error'];
}
}
else
{
echo"WORKS";
}
The most easiest way to send back the image to a browser is via using a URL.
Process the image
Save the image somewhere on your sever
Send the URL back to browser.
Use a tag at the browser and show your image.
<?PHP
$imgFile="";
if($_FILES['photo']['tmp_name'])
{
///Your existing code
$imgFile="http://" . $_SERVER['HTTP_HOST'] .'/Your image url here';
//Ex:\\ http://yourserver.com/images/1.jpg -
//you can take this from your move_upload_file
}
?>
<img src="<?PHP echo $imgFile; ?>" />
Useful links How to receive a file via HTTP PUT with PHP
Even for a restful service u can use json or xml to send the image url back. PUT is not a good idea unless u need to send back image data for some reason. May be u should rethink your logic?
The mistakes was:
strlen($image) strlen if wrong, must be filesize and in my url I had www. It's not netion in my post but it was mistake.
More experienced programmer helped me.
r.php to read stream:
$res = file_get_contents("php://input");
$file = fopen('1.txt', "w");
fputs($file, $res);
fclose($file);
var_dump($res);
s.php to get stream and to init r.php
$image = fopen('/var/www/testfiles/1.jpg', "rb");
var_dump($image);
$ch = curl_init();
/* Set cURL options. */
curl_setopt($ch, CURLOPT_URL, "http://url withot www/r.php");
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_INFILE, $image);
curl_setopt($ch, CURLOPT_INFILESIZE, filesize('/var/www/testfiles/1.jpg'));
/* Execute the PUT and clean up */
$result = curl_exec($ch);
fclose($image); //recommended to close the fileshandler after action
curl_close($ch);
die("OK");

Categories