Hi i am using php file_get_contents method to get content. For getting high content it makes problem about bandwidth. I like to get gzip format data to get and decode to it later.
I collected a sample one but it show quite similar content length. here it is
<?php
function fetchUrl( $url, $gzip = false ) {
$raw = file_get_contents( $url, false, $context = stream_context_create( array(
'http' => array(
'method' => 'GET',
'header' => 'Accept-Encoding:' . ( $gzip ? 'gzip,deflate' : 'identity' ) . "\r\n",
)
) ) );
if ( $raw === false ) {
return false;
}
return $gzip ? gzdecode( $raw ) : $raw;
}
$src1 = fetchUrl( 'http://www.google.com' );
$src2 = fetchUrl( 'http://www.google.com', true );
echo strlen($src1). "<br>";
echo strlen($src2);
?>
which results
52233
52232
if there a better solution please help me or redirect me any solution present this site.
NB: i searched but do not get exact one, if i may wrong then provide that link where i get proper solution.
TIA.
I am new in PHP and I am trying to access file of another website of mine. So on my web #1 I am trying to send a POST request like this:
<?php
$url = 'http://localhost/modul_cms/admin/api.php'; //Web #2
$data = array(
"Action" => "getNewestRecipe",
"Secret" => "61cbe6797d18a2772176b0ce73c580d95f79500d77e45ef810035bc738aef99c3e13568993f735eeb0d3c9e73b22986c57da60a0b2d6413c5dc32b764cc5897a",
"User" => "joomla localhost",
);
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
echo $result;
if($result === FALSE){
echo "Not working connection :(";
}else{
echo "HOORAY!";
var_dump($result);
}
And on my web #2 I have some kind of receiver I made. Now I need to return after selecting stuff from my database array of data. So I have code like this on my web #2:
<?php
$action = isset( $_POST["action"] ) ? $_POST["action"] : "";
$secret = isset( $_POST["secret"] ) ? $_POST["secret"] : "";
$user = isset( $_POST["user"] ) ? $_POST["user"] : "";
if(!empty($secret)){
if(!empty($user)){
switch($action){
case 'getNewestRecipe':
getNewestRecipe();
break;
case '':
error();
break;
default:
error();
break;
}
}
}
/* *************** FUNCTIONS ************* */
function getNewestRecipe(){
return array("msg" => "Here is your message!");
}
The problem is everything I get on my web #1 from the response is actually the echo I have there for knowing that the HTTP request reached something (so I've got the message "HOORAY!") but the
var_dump($response)
has empty value (not NULL or something it's literally this):
C:\Program Files (x86)\Ampps\www\joomla30\templates\protostar\index.php:214:string '' (length=0)
Thank you for any help!
On web#1 you are sending "Secret","User","Action" in upper-case, but on web#2 you are accessing $_POST['secret'] (lower-case). Because of this your code never gets to the call of getNewestRecipe() nor to your error() call, thus there is no content / a blank page, but also no error.
Also, you need to output the array your function returns in some way.
An array cannot simply be echod, so you need to serialize it. I suggest using json_encode: echo json_encode(getNewestRecipe());
I've been getting this warning after defining the $image variable using the file_get_contents() function:
Warning: file_get_contents(): Filename cannot be empty
Even though I passed a value to $formname with this method call :
Image::uploadImage('postimg', "UPDATE dry_posts SET postimg = :postimg WHERE id = :postid", array(':postid' => $postid),array(':postimg' => $postimg));
$postimg is a file variable in a form. I've tried checking if the file exists, which solved the error but of course nothing was being executed. It seems to not like it whenever I use file_get_contents(), how do I turn this around?
<?php
include_once("connect.php");
class Image
{
public static function uploadImage($formname,$query,$params)
{
$formname = "";
$response = "";
$image = "";
echo 'hello';
//if(file_exists($formname))
//{
echo 'hello';
$image = base64_encode(file_get_contents($_FILES[$formname]['tmp_name']));
//}
$options = array('http'=>array(
'method'=>"POST",
'header'=>"Authorization: Bearer access code here\n".
"Content-Type: application/x-www-form-urlencoded",
'content'=>$image
));
$context = stream_context_create($options);
$imgurURL = "https://api.imgur.com/3/image";
if ($_FILES[$formname]['size'] > 10240000) {
die('Image too big, must be 10MB or less!');
}
//if(file_exists($formname))
//{
echo 'hell0';
$response = file_get_contents($imgurURL, false, $context);
//}
$response = json_decode($response);
//from
//$prearams = array($formname=>$response->data->link);
//$params = $preparams + $params;
//from changes
//$params=array(':postid'=>$postid);
$params = array(':postid' => $params['postid'], ':postimg' => $params['postimg']);
connect::query($query,$params);
}
}
?>
You are unsetting "$formname" here? $formname = ""; So doesn't matter if you pass it in the method call, it will always be empty
Im looking to only display certain things from pages like this: http://sc2ranks.com/api/psearch/am/MxGPezz/1t/division/Felanis%20Sierra?appKey=sentinelgaming.net . So far I am able to display something but its not even the correct number, using the php below. Can someone show me how I would display the "achivement-points" of this player from this XML web page?
$url = 'http://sc2ranks.com/api/psearch/am/MxGPezz/1t/division/Felanis%20Sierra?appKey=sentinelgaming.net';
$xml = file_get_contents($url);
echo $xml->achievement-points;
Thanks
The content-type of this file varies depending on the Accept header or the format query parameter. It seems you can retrieve at least XML or JSON.
The default you get from file_get_contents() will be JSON because it does not include an Accept request header, but the default from a browser will be XML because browsers usually include an XML mime type in their Accept request header.
To get JSON:
$url = 'http://sc2ranks.com/api/psearch/am/MxGPezz/1t/division/Felanis%20Sierra?appKey=sentinelgaming.net';
// &format=json is not strictly necessary,
// but it will give you fewer surprises
$json = file_get_contents($url.'&format=json');
$records = json_decode($json);
echo $records[0]->achievement_points, "\n";
To get XML:
$sxe = simplexml_load_file($url.'&format=xml');
echo (string) $sxe->record->{'achievement-points'}, "\n";
To use the $sxe object see this SimpleXML cheat sheet.
Instead of using the format param you could set the Accept header. You can also add some abstraction to getting a url so that you can retrieve the content type and encoding as well. See example below.
function get_url($url, $context=null) {
$response = file_get_contents($url, false, $context);
$ctypeheaders = preg_grep('/^Content-Type:\s/i', $http_response_header);
$ctype = NULL;
if ($ctypeheaders) {
$ctype = end($ctypeheaders);
$ctype = end(explode(':', $ctype, 2));
$ctype = explode(';', $ctype, 2);
$charset = isset($ctype[1]) ? $ctype[1] : '';
if ($charset && preg_match('/charset\s*=\s*([^\s]+)/i', $charset, $matches)) {
$charset = $matches[1];
}
$ctype[1] = $charset;
$ctype = array_map('trim', $ctype);
}
return array($response, $ctype);
}
You can then use get_url() like so:
// With no accept header, just see what we get:
list($content, $contenttype) = get_url($url);
list($type, $encoding) = $contenttype;
// $type will be 'application/xml' or 'application/json'
// $encoding is very handy to know too
// Or we can specify an accept header:
$opt_accept_xml = stream_context_create(array(
'http' => array(
'header' => "Accept: application/xml\r\n"
)
));
list($content, $contenttype) = get_url($url, $opt_accept_xml);
Maybe:
echo $xml->record[0]->achievement-points;
I’ve run into a limitation in the cURL bindings for PHP. It appears there is no easy way to send the same multiple values for the same key for postfields. Most of the workarounds I have come across for this have involved creating the URL encoded post fields by hand tag=foo&tag=bar&tag=baz) instead of using the associative array version of CURLOPT_POSTFIELDS.
It seems like a pretty common thing to need to support so I feel like I must have missed something. Is this really the only way to handle multiple values for the same key?
While this workaround might be considered workable (if not really annoying), my main problem is that I need to be able to do multiple values for the same key and also support file upload. As far as I can tell, file upload more or less requires to use the associate arravy version of CURLOPT_POSTFIELDS. So I feel like I am stuck.
I have posted about this problem in more detail on the cURL PHP mailing list in the hopes that someone there has some ideas about this.
Suggestions or hints on where I can look for more information on this are greatly appreciated!
I ended up writing my own function to build a custom CURLOPT_POSTFIELDS string with multipart/form-data. What a pain.
function curl_setopt_custom_postfields($ch, $postfields, $headers = null) {
// $postfields is an assoc array.
// Creates a boundary.
// Reads each postfields, detects which are #files, and which values are arrays
// and dumps them into a new array (not an assoc array) so each key can exist
// multiple times.
// Sets content-length, content-type and sets CURLOPT_POSTFIELDS with the
// generated body.
}
I was able to use this method like this:
curl_setopt_custom_postfields($ch, array(
'file' => '#/path/to/file',
'tag' => array('a', 'b', 'c'),
));
I am not certain of CURLOPT_HTTPHEADER stacks, so since this method calls it, I made certain that the function would allow for the user to specify additonal headers if needed.
I have the full code available in this blog post.
If you use tag[] rather than tag for the name, PHP will generate an array for you, in other words, rather than
tag=foo&tag=bar&tag=baz
You need
tag[]=foo&tag[]=bar&tag[]=baz
Note that when urlencoded for transmission this should become
tag%5B%5D=foo&tag%5B%5D=bar&tag%5B%5D=baz
Vote for PHP Bug #51634.
Try #BeauSimensen's answer.
Guzzle can do this. See an example below.
$client = new \GuzzleHttp\Client();
$client->request('POST', $url, [
'multipart' => [
[ 'name' => 'foo', 'contents' => 'bar' ],
[ 'name' => 'foo', 'contents' => 'baz' ],
]
]);
I ran into the same issue. But I was able to solve it this way.
for($cnt = 0; $cnt < count($siteRows); $cnt++)
{
$curlParams['site_ids['.$cnt.']'] = $siteRows[$cnt]->site_id;
}
Works for files too:
for($cnt = 0; $cnt < count($imageRows); $cnt++)
{
$curlParams['product_images['.$cnt.']'] = '#'.$imageRows[$cnt]->full_path;
}
I got it working using:
curl_setopt($ch, CURLOPT_POSTFIELDS,array('tag[0]'=>'val0','tag[1]'=>'val1'));
then $_POST results in: $_POST['tag'][0] = 'val0' and $_POST['tag'][1] = 'val1'
I think the established standard for multiple values in one key (or the same key) is to have it concatenated with a delimiter, such as for multiple selections of option lists in form elements. I believe this delimiter is the tab character (\t) or the pipe symbol (|).
If the keyname is terminated with [] (like tag[]), PHP will automatically convert the values into an array for your convenience.
lImbus and paul, thank you for your input.
If I had control over the form I am posting to, I could probably find an alternate solution to this problem. However, I do not have any control over the form. And I am almost positive that the software reading the post is not PHP and does not obey the tag[] standards.
Even if it did, cURL does not seem to obey the tag[] syntax either. Basically, I tried the following and neither worked...
curl_setopt($ch, CURLOPT_POSTFIELDS, array('file' => '#/pathtofile', 'tag[]' => array('a', 'b', 'c'));
curl_setopt($ch, CURLOPT_POSTFIELDS, array('file' => '#/pathtofile', 'tag' => array('a', 'b', 'c'));
And again, I don't think that passing tag[] would work anyway as the form I am posting to is actually looking for 'tag' and not 'tag[]'.
I am really starting to get the feeling that the cURL PHP bindings really have no support for this. Which seems so surprising to me. It seems like it can do quite literally anything else, yet it is unable to do something simple like this?
DON'T USE GUZZLE:
# at your command line start php interactive
user#group:~:php -a
php > $arr=array('var' => array(1,2,3,4));
php > echo http_build_query($arr);
var%5B0%5D=1&var%5B1%5D=2&var%5B2%5D=3&var%5B3%5D=4
php > echo urldecode(http_build_query($arr));
var[0]=1&var[1]=2&var[2]=3&var[3]=4
So, you need http_build_query where you pass a hash array of key-values; your (array) variable is entered as a key with value a array instead a scalar value like 'var' => array(1,2,3,4). Now, http_build_query can format the post fields of curl command:
$fields = array('key1' => 'value1', 'var' => array(1,2,3,4));
$curlPost = \http_build_query($fields);
curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
that's 3 lines of code! how many 1000s of code lines are in Guzzle? (*)
So far, I used curl to:
manage Google OAuth protocol with success
connect with APIs like mailgun
handle paypal smart buttons
that's a replacement of million of lines with some 100s!
(*): the result of http_build_query can be formatted further according your needs.
I ran into the same problem in which I had to send a parameter which has to be an array from a PHP server to another server that does not use '[]' for mixing values with the same key along with a file.
In Laravel 8 I could achieve this goal with Http client (of course Http client uses guzzle).
Here is a sample of my code.
Illuminate\Support\Facades\Http::attach('file', $fileContents, 'file-name')
->post('https://destination' , [['name' => 'tag', 'content' => 'foo'], ['name' => 'tag', 'content' => 'bar']])
I found this answer online and want to post it here before it disappears:
http://yeehuichan.wordpress.com/2011/08/07/sending-multiple-values-with-the-same-namekey-in-curl-post/
function curl_setopt_custom_postfields($ch, $postfields, $headers = null) {
$algos = hash_algos();
$hashAlgo = null;
foreach ( array('sha1', 'md5') as $preferred ) {
if ( in_array($preferred, $algos) ) {
$hashAlgo = $preferred;
break;
}
}
if ( $hashAlgo === null ) { list($hashAlgo) = $algos; }
$boundary =
'----------------------------' .
substr(hash($hashAlgo, 'cURL-php-multiple-value-same-key-support' . microtime()), 0, 12);
$body = array();
$crlf = "\r\n";
$fields = array();
foreach ( $postfields as $key => $value ) {
if ( is_array($value) ) {
foreach ( $value as $v ) {
$fields[] = array($key, $v);
}
} else {
$fields[] = array($key, $value);
}
}
foreach ( $fields as $field ) {
list($key, $value) = $field;
if ( strpos($value, '#') === 0 ) {
preg_match('/^#(.*?)$/', $value, $matches);
list($dummy, $filename) = $matches;
$body[] = '--' . $boundary;
$body[] = 'Content-Disposition: form-data; name="' . $key . '"; filename="' . basename($filename) . '"';
$body[] = 'Content-Type: application/octet-stream';
$body[] = '';
$body[] = file_get_contents($filename);
} else {
$body[] = '--' . $boundary;
$body[] = 'Content-Disposition: form-data; name="' . $key . '"';
$body[] = '';
$body[] = $value;
}
}
$body[] = '--' . $boundary . '--';
$body[] = '';
$contentType = 'multipart/form-data; boundary=' . $boundary;
$content = join($crlf, $body);
$contentLength = strlen($content);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Length: ' . $contentLength,
'Expect: 100-continue',
'Content-Type: ' . $contentType,
));
curl_setopt($ch, CURLOPT_POSTFIELDS, $content);
}
And to use it:
curl_setopt_custom_postfields($ch, array(
'file' => '#a.csv',
'name' => array('James', 'Peter', 'Richard'),
));