I have some process in page. It's downloading a file.
<?php
// getting file with CURL
$ch = curl_init ('http://adress.com/file.csv');
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
curl_setopt($ch, CURLOPT_TIMEOUT,7500);
$rawdata=curl_exec($ch);
curl_close ($ch);
// End Curl Process
// SAVE FILE
$name = Rand(100000,1000000);
$fp = fopen('files/'.$name.'.csv','w');
fwrite($fp, $rawdata);
fclose($fp);
// END SAVE PROCESS
// REDIRECT OTHER PAGE
**header('Location: x.php');**
// END OF PAGE
?>
This is allright. But there is a problem. It redirects without complete process. I want to redirect after all processes are done. The file is empty when i redirect with that method.
What must I do? How can i redirect page after all processes are done? php or javascript/jquery.
I think set a callback when the header is complete is the best solution.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.php.net/');
// here is the hack - Set callback function for headers
curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
curl_exec($ch);
curl_close($ch);
//Callback function for header
function read_header($ch, $string)
{
if (trim($string) == 'HTTP/1.1 200 OK')
header("location: http://www.php.net");
}
Your code should be fine, and should complete the process before redirecting.
PHP runs in a single thread, so the next statement won't be executed until the previous one completes. This means that your header() line won't execute until fwrite() has finished writing the file.
In fact, setting a Location header doesn't even mean the PHP script stops. You can test this by creating a dummy file and running unlink() on it after issuing the Location header. The file will still be deleted. All that Location does is sends a new location to your browser. Your browser then retrieves the new page before the old one is done running.
You can set sleep(seconds) and check if it's enough for complete process.
Also you can put a simple check:
$start_size = 0;
while (1) {
$new_file_size = filesize($filename);
if ($start_size != $new_file_size) {
$start_size = $new_file_size;
sleep(30)
} else {
break;
}
}
If you aren't returning the file to the client, you can do the following:
ignore_user_abort();
header("Content-Length: 0", true, HTTP_RESPONSE_204_NO_CONTENT);
header("Connection: close", true);
flush();
This will return control back to the client and close the browser connection, but the server-side process will continue to work.
However, I agree with #AgentConundrum that the header() line won't be executed until the other processes are complete.
Related
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.
I'm trying to grab a photo from Google Place Photos using curl and save it on my server.
The request format as per the Google API documentation is like this:
https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=CoQBegAAAFg5U0y-iQEtUVMfqw4KpXYe60QwJC-wl59NZlcaxSQZNgAhGrjmUKD2NkXatfQF1QRap-PQCx3kMfsKQCcxtkZqQ&sensor=true&key=AddYourOwnKeyHere
So I tried this function:
function download_image1($image_url, $image_file){
$fp = fopen ($image_file, 'w+');
$ch = curl_init($image_url);
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // enable if you want
curl_setopt($ch, CURLOPT_FILE, $fp); // output to file
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 1000); // some large value to allow curl to run for a long time
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0');
// curl_setopt($ch, CURLOPT_VERBOSE, true); // Enable this line to see debug prints
curl_exec($ch);
curl_close($ch); // closing curl handle
fclose($fp); // closing file handle
}
download_image1($photo, "test.jpg");
..where $photo holds the request url.
This is not working, it saves an empty image with header errors, it probably is because the request is not the actual url of the photo. Also, in the request url, it's not possible to know which image extension I'm going to get (jpg, png, gif, etc) so that's another problem.
Any help on how to save the photos appreciated.
EDIT: I get the header errors "Can't read file header" in my image viewer software when I try to open the image. The script itself doesn't show any errors.
I found a solution here:
http://kyleyu.com/?q=node/356
It gives a very useful function to return the actual URL after redirection:
function get_furl($url)
{
$furl = false;
// First check response headers
$headers = get_headers($url);
// Test for 301 or 302
if(preg_match('/^HTTP\/\d\.\d\s+(301|302)/',$headers[0]))
{
foreach($headers as $value)
{
if(substr(strtolower($value), 0, 9) == "location:")
{
$furl = trim(substr($value, 9, strlen($value)));
}
}
}
// Set final URL
$furl = ($furl) ? $furl : $url;
return $furl;
}
So you pass the Google Place Photo request uRL to this function and it returns the actual URL of the photo after the redirection which then can be used with CURL. It also explains that sometimes, the curl option curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); doesn't always work.
https://stackoverflow.com/a/23540352/2979237
We can minimize the above code to change as adding 1 as the second parameter of get_header() function like $headers = get_headers($url, 1);. that will return the associate values.
I want to do 300 redirect by php but first I want script will check whether the site is online or not if online then it will redirect else it will show unable to redirect. Can any one tell me how is possible?
thanks
This should do it (edited for betterness)
$destination = 'http://www.google.com';
$ch = curl_init($destination);
// use request type HEAD because it's faster and lighter
curl_setopt($ch, CURLOPT_NOBODY, true);
// prevent curl from dumping any output
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// prevent curl from producing any output
curl_setopt($ch, CURLOPT_HEADER, false);
// run request
curl_exec($ch);
// consider request a success if the HTTP Code is less than 400 (start of errors)
// change this to whatever you expect to get, e.g. "equal to 200 (OK)"
$success = (bool) ((int)curl_getinfo($ch, CURLINFO_HTTP_CODE) < 400);
curl_close($ch);
// redirect or die
if ($success) {
header('Location: ' . $destination, true, 301);
} else {
die('Unable to redirect to '.$destination.'');
}
I want to load a txt file which is not there yet. I mean I'll get a pending status from server. And the page will only get respond 200 status from server when the txt file is there. Or there is no way to do that?
do{
$file = #file_get_contents("file.txt");
sleep(1);
}while(empty($file));
If we are talking about remote server, you should use cURL, and "load" file every couple of seconds, if string is empty, means there is no file.
This should be checked async.
function curl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_close ($ch);
return curl_exec($ch);
}
do{
$file = curl("http://example.com/file.txt");
sleep(5);
}while(empty($file));
$.post("your/url", {}, function(file) {
// since this is a success callback, once you are inside this block,
// you got your file.
// If you return anything other than 200 OK, this callback wouldn't get called
});
When I execute the following code it takes between 10-12 seconds to respond.
Is the problem with Twitter or with our server?
I really need to know as this is part of the code to display tweets on our website and a 12 second load time is just not acceptable!
function get_latest_tweets($username)
{
print "<font color=red>**". time()."**</font><br>";
$path = 'http://api.twitter.com/1/statuses/user_timeline/' . $username.'.json?include_rts=true&count=2';
$jason = file_get_contents($path);
print "<font color=red>**". time()."**</font><br>";
}
Thanks
When you put the URL into your browser (http://api.twitter.com/1/statuses/user_timeline/username.json?include_rts=true&count=2) how long does it take for the page to appear? If it's quick then you need to start the search at your server.
use curl instead of file_get_contents() to request, so that response will be compressed. Here is the curl function which iam using.
function curl_file_get_contents($url)
{
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,$url); //The URL to fetch. This can also be set when initializing a session with curl_init().
curl_setopt($curl,CURLOPT_RETURNTRANSFER,TRUE); //TRUE to return the transfer as a string of the return value of curl_exec() instead of outputting it out directly.
curl_setopt($curl,CURLOPT_ENCODING , "gzip");
curl_setopt($curl, CURLOPT_FAILONERROR, TRUE); //To fail silently if the HTTP code returned is greater than or equal to 400.
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);
$contents = curl_exec($curl);
curl_close($curl);
return $contents;
}