How use CURLOPT_WRITEFUNCTION when download a file by CURL - php

My Class for download file direct from a link:
MyClass{
function download($link){
......
$ch = curl_init($link);
curl_setopt($ch, CURLOPT_FILE, $File->handle);
curl_setopt($ch,CURLOPT_WRITEFUNCTION , array($this,'__writeFunction'));
curl_exec($ch);
curl_close($ch);
$File->close();
......
}
function __writeFunction($curl, $data) {
return strlen($data);
}
}
I want know how to use CRULOPT_WRITEFUNCTION when download file.
Above code if i remove line:
curl_setopt($ch,CURLOPT_WRITEFUNCTION , array($this,'__writeFunction'));
Then it will run good, i can download that file.But if i use CURL_WRITEFUNCTION option i can't download file.

I know this is an old question, but maybe my answer will be of some help for you or someone else. Try this:
function get_write_function(){
return function($curl, $data){
return strlen($data);
}
}
I don't know exactly what you want to do, but with PHP 5.3, you can do a lot with the callback. What's really great about generating a function in this way is that the values passed through the 'use' keyword remain with the function afterward, kind of like constants.
function get_write_function($var){
$obj = $this;//access variables or functions within your class with the object variable
return function($curl, $data) use ($var, $obj) {
$len = strlen($data);
//just an example - you can come up with something better than this:
if ($len > $var){
return -1;//abort the download
} else {
$obj->do_something();//call a class function
return $len;
}
}
}
You can retrieve the function as a variable as follows:
function download($link){
......
$var = 5000;
$write_function = $this->get_write_function($var);
$ch = curl_init($link);
curl_setopt($ch, CURLOPT_FILE, $File->handle);
curl_setopt($ch, CURLOPT_WRITEFUNCTION , $write_function);
curl_exec($ch);
curl_close($ch);
$File->close();
......
}
That was just an example. You can see how I used it here: Parallel cURL Request with WRITEFUNCTION Callback. I didn't actually test all of this code, so there may be minor errors. Let me know if you have problems, and I'll fix it.

<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_BUFFERSIZE, 8096);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, 'http://blog.ronnyristau.de/wp-content/uploads/2008/12/php.jpg');
$content = curl_exec($ch);
curl_close($ch);
$out = fopen('/tmp/out.png','w');
if($out){
fwrite($out, $content);
fclose($out);
}

Why do you use curl to download a file? Is there a special reason? You can simply use fopen and fread
I have written a small class for it.
<?php
class Utils_FileDownload {
private $source;
private $dest;
private $buffer;
private $overwrite;
public function __construct($source,$dest,$buffer=4096,$overwrite=false){
$this->source = $source;
$this->dest = $dest;
$this->buffer = $buffer;
$this->overwrite = $overwrite;
}
public function download(){
if($this->overwrite||!file_exists($this->dest)){
if(!is_dir(dirname($this->dest))){mkdir(dirname($this->dest),0755,true);}
if($this->source==""){
$resource = false;
Utils_Logging_Logger::getLogger()->log("source must not be empty.",Utils_Logging_Logger::TYPE_ERROR);
}
else{ $resource = fopen($this->source,"rb"); }
if($this->source==""){
$dest = false;
Utils_Logging_Logger::getLogger()->log("destination must not be empty.",Utils_Logging_Logger::TYPE_ERROR);
}
else{ $dest = fopen($this->dest,"wb"); }
if($resource!==false&&$dest!==false){
while(!feof($resource)){
$read = fread($resource,$this->buffer);
fwrite($dest,$read,$this->buffer);
}
chmod($this->dest,0644);
fclose($dest); fclose($resource);
return true;
}else{
return false;
}
}else{
return false;
}
}
}

It seems like cURL uses your function instead of writing to the request once CURLOPT_WRITEFUNCTION is specified.
So the correct solution would be :
MyClass{
function download($link){
......
$ch = curl_init($link);
curl_setopt($ch, CURLOPT_FILE, $File->handle);
curl_setopt($ch,CURLOPT_WRITEFUNCTION , array($this,'__writeFunction'));
curl_exec($ch);
curl_close($ch);
$File->close();
......
}
function __writeFunction($curl, $data) {
echo $data;
return strlen($data);
}
}
This can also handle binary files as well.

Related

HTTP Requests made with file_get_contents() share the same session data?

I've got a problem...
I've a MVC-like framework and the redirect mechanism allows me too get snippets of HTML code generated by PHP on a remote host.
I'm getting these snippets by using the file_get_contents() function, with allow_url_fopen turned on.
The problem is the fact I use session data inside these code fragments and the session data is being lost every time. I'm assuming this new request is not sharing the same session data and therefore I need a way to get these fragments without losing my session data.
Any suggestions?
If the files your accessing are on the same server as the calling file then you might as well use include(); like #user574632's answer.
But if not, to keep the session you will need to handle the cookies the server sends;
Sessions are cookie based, server sets the session cookie your browser picks it up and uses it for all subsequent requests.
By default file_get_contents wont handle cookies, so your need to grab the header from the server by accessing $http_response_header array and then match with regex the Set-Cookie: header then store that and on following requests use the cookie and create a stream context with the cookie added to the header and pass that to fgc:
<?php
function get_cookies() {
//check cookies folder - or make it
if(!file_exists('./cookies/')){
mkdir('./cookies/', 0755, true);
}
$return = null;
foreach(glob("./cookies/*.txt") as $file) {
$return .= file_get_contents($file).';';
}
return $return;
}
function save_cookies($http_response_header) {
print_r($http_response_header);
foreach($http_response_header as $header) {
if(substr($header, 0, 10) == 'Set-Cookie'){
if(preg_match('#Set-Cookie: (([^=]+)=[^;]+)#i', $header, $matches)) {
$fp = fopen('./cookies/'.$matches[2].'.txt', 'w');
fwrite($fp, $matches[1]);
fclose($fp);
}
}
}
}
$opts = array('http' =>
array('header'=>'Cookie: '.get_cookies()."\r\n")
);
$context = stream_context_create($opts);
$contents = file_get_contents('http://mywebsite.com/snippets/', false, $context);
save_cookies($http_response_header);
echo $contents;
?>
Alternatively you should use curl instead its faster and handles cookies fine.
So something like the following, use curl and then revert to fgc if curl is not present, all wrapped up with cookie support in a class, so the 3 functions are contained:
<?php
//example usage
echo new curl_get_contents('http://example.com/page_that_needs_sessions');
class curl_get_contents{
public $result;
function __construct($url){
$this->curl_rev_fgc($url);
}
function __toString(){
return $this->result;
}
private function get_cookies() {
$return = null;
foreach(glob("./cookies/*.txt") as $file) {
$return .= file_get_contents($file).';';
}
return $return;
}
private function save_cookies($http_response_header) {
foreach($http_response_header as $header) {
if(substr($header, 0, 10) == 'Set-Cookie'){
if(preg_match('#Set-Cookie: (([^=]+)=[^;]+)#i', $header, $matches)) {
$fp = fopen('./'.$matches[2].'.txt', 'w');
fwrite($fp, $matches[1]);
fclose($fp);
}
}
}
}
private function curl_rev_fgc($url){
//check cookies folder - or make it
if(!file_exists('./cookies')){
mkdir('./cookies/', 0755, true);
}
$usragent = 'Mozilla/5.0 (compatible; Yourbot/0.1; +https://yoursite/bot.html)';
//Check curl is installed or revert to file_get_contents()
$curl = function_exists('curl_init') ? true : false;
if($curl){
$opts = array(
'http' => array(
'method' => "GET",
'header' => 'Cookie: '.$this->get_cookies().'\r\n', // cookie in fgc support
'user_agent' => $usragent)
);
$context = stream_context_create($opts);
$result = #file_get_contents($url, false, $context);
$this->save_cookies($http_response_header);
if(empty($result)){
$this->result = 'Error fetching: '.htmlentities($url);
}else{
$this->result = $result;
}
return;
}
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
curl_setopt($curl, CURLOPT_USERAGENT, $usragent);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
if(!file_exists('./cookies/curl.txt')){
file_put_contents('./cookies/curl.txt',null);
}
curl_setopt($curl, CURLOPT_COOKIEFILE, './cookies/curl.txt');
curl_setopt($curl, CURLOPT_COOKIEJAR, './cookies/curl.txt');
$result = curl_exec($curl);
if(empty($result)){
$this->result = 'Error fetching: '.htmlentities($url);
}else{
$this->result = $result;
}
curl_close($curl);
return;
}
}
?>
Use include instead. If you need to read the output into a variable to display later/elsewhere in the code, as suggested in the comments, use the output buffer:
ob_start();
include('path/to/file.php');
$included = ob_get_clean();
//nothing has been output to the browser yet
//later on
echo $included;

Is there an alternative to file_get_contents?

Is there an alternative to file_get_contents? This is the code I'm having issues with:
if ( !$img = file_get_contents($imgurl) ) { $error[] = "Couldn't find the file named $card.$format at $defaultauto"; }
else {
if ( !file_put_contents($filename,$img) ) { $error[] = "Failed to upload $filename"; }
else { $success[] = "All missing cards have been uploaded"; }
}
I tried using cURL but couldn't quite figure out how to accomplish what this is accomplishing. Any help is appreciated!
There are many alternatives to file_get_contents I've posted a couple of alternatives below.
fopen
function fOpenRequest($url) {
$file = fopen($url, 'r');
$data = stream_get_contents($file);
fclose($file);
return $data;
}
$fopen = fOpenRequest('https://www.example.com');// This returns the data using fopen.
curl
function curlRequest($url) {
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($c);
curl_close($c);
return $data;
}
$curl = curlRequest('https://www.example.com');// This returns the data using curl.
You could use one of these available options with the data stored in a variable to preform what you need to.

How can I read all the <status> tags from the Twitter timeline for a user?

I am trying to read twitter timeline with cURL, and for some reason I am unable to use preg_match. Here's my current code, do you see any issues?
$feed = "http://twitter.com/statuses/user_timeline/antonpug.xml?count=3";
function parse_feed($feed) {
//$matches = Array();
preg_match_all("/<status>(.*?)<\/status>/", $content[0], $matches);
return $matches[0];
//$stepOne = explode("<content type=\"html\">", $feed);
//$stepTwo = explode("</content>", $stepOne[1]);
//$tweet = $stepTwo[0];
//$tweet = htmlspecialchars_decode($tweet,ENT_QUOTES);
//return $tweet;
}
//Initialize the Curl session
$ch = curl_init();
//Set curl to return the data instead of printing it to the browser.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//Set the URL
curl_setopt($ch, CURLOPT_URL, $feed);
//Execute the fetch
$twitterFeed = curl_exec($ch);
//Close the connection
curl_close($ch);
//$twitterFeed = file_get_contents($feed);
echo(parse_feed($twitterFeed));
I guess the better idea would be to use simplexml to work with XML as with object.
Your function then would be something like
function parse_feed($feed) {
$xml = simplexml_load_string($feed);
if(isset($xml->status)) {
return $xml->xpath('status');
} else {
return false;
}
}
It will return simplexml object.

Using curl as an alternative to fopen file resource for fgetcsv

Is it possible to make curl, access a url and the result as a file resource? like how fopen does it.
My goals:
Parse a CSV file
Pass it to fgetcsv
My obstruction: fopen is disabled
My chunk of codes (in fopen)
$url = "http://download.finance.yahoo.com/d/quotes.csv?s=USDEUR=X&f=sl1d1t1n&e=.csv";
$f = fopen($url, 'r');
print_r(fgetcsv($f));
Then, I am trying this on curl.
$curl = curl_init();
curl_setopt($curl, CURLOPT_VERBOSE, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $param);
curl_setopt($curl, CURLOPT_URL, $url);
$content = #curl_exec($curl);
curl_close($curl);
But, as usual. $content already returns a string.
Now, is it possible for curl to return it as a file resource pointer? just like fopen? Using PHP < 5.1.x something. I mean, not using str_getcsv, since it's only 5.3.
My error
Warning: fgetcsv() expects parameter 1 to be resource, boolean given
Thanks
Assuming that by fopen is disabled you mean "allow_url_fopen is disabled", a combination of CURLOPT_FILE and php://temp make this fairly easy:
$f = fopen('php://temp', 'w+');
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_FILE, $f);
// Do you need these? Your fopen() method isn't a post request
// curl_setopt($curl, CURLOPT_POST, true);
// curl_setopt($curl, CURLOPT_POSTFIELDS, $param);
curl_exec($curl);
curl_close($curl);
rewind($f);
while ($line = fgetcsv($f)) {
print_r($line);
}
fclose($f);
Basically this creates a pointer to a "virtual" file, and cURL stores the response in it. Then you just reset the pointer to the beginning and it can be treated as if you had opened it as usual with fopen($url, 'r');
You can create a temporary file using fopen() and then fwrite() the contents into it. After that, the newly created file will be readable by fgetcsv(). The tempnam() function should handle the creation of arbitrary temporary files.
According to the comments on str_getcsv(), users without access to the command could try the function below. There are also various other approaches in the comments, make sure you check them out.
function str_getcsv($input, $delimiter = ',', $enclosure = '"', $escape = '\\', $eol = '\n') {
if (is_string($input) && !empty($input)) {
$output = array();
$tmp = preg_split("/".$eol."/",$input);
if (is_array($tmp) && !empty($tmp)) {
while (list($line_num, $line) = each($tmp)) {
if (preg_match("/".$escape.$enclosure."/",$line)) {
while ($strlen = strlen($line)) {
$pos_delimiter = strpos($line,$delimiter);
$pos_enclosure_start = strpos($line,$enclosure);
if (
is_int($pos_delimiter) && is_int($pos_enclosure_start)
&& ($pos_enclosure_start < $pos_delimiter)
) {
$enclosed_str = substr($line,1);
$pos_enclosure_end = strpos($enclosed_str,$enclosure);
$enclosed_str = substr($enclosed_str,0,$pos_enclosure_end);
$output[$line_num][] = $enclosed_str;
$offset = $pos_enclosure_end+3;
} else {
if (empty($pos_delimiter) && empty($pos_enclosure_start)) {
$output[$line_num][] = substr($line,0);
$offset = strlen($line);
} else {
$output[$line_num][] = substr($line,0,$pos_delimiter);
$offset = (
!empty($pos_enclosure_start)
&& ($pos_enclosure_start < $pos_delimiter)
)
?$pos_enclosure_start
:$pos_delimiter+1;
}
}
$line = substr($line,$offset);
}
} else {
$line = preg_split("/".$delimiter."/",$line);
/*
* Validating against pesky extra line breaks creating false rows.
*/
if (is_array($line) && !empty($line[0])) {
$output[$line_num] = $line;
}
}
}
return $output;
} else {
return false;
}
} else {
return false;
}
}

Function Inside Function Can't Find Variable

I'm trying to use the curl headerfunction opt from a class. I've tried putting the functions inside the class normally, but curl can't find them that way. So I put them inside the function I need it in. Here's the part of code that's applicable:
$ht = array();
$t = array();
function htWrite($stream,$buffer)
{
$ht[] = $buffer;
return strlen($buffer);
}
function tWrite($stream,$buffer)
{
$t[] = $buffer;
return strlen($buffer);
}
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'htWrite');
curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'tWrite');
When I put an echo statement in htWrite for the buffer, it echos out just fine. But if I do a print_r statement on $ht later, it says that it's empty. Further investigation says that it's creating its own $ht variable, because if I remove that line, $ht is null according to the function. So what can I do to fix this?
You need to look at how you can specify object methods as callbacks:
class Foo {
public function Bar() {
// do whatever
}
public function Test() {
$ch = curl_init('http://www.google.com');
curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, 'Bar'));
}
}

Categories