Hello i have some problem with doing a force download.
Here is my code :
public function download(Request $request, $id) {
$document = Document::find($id);
$s3 = Storage::disk('s3');
$name = substr($document->link, strrpos($document->link, '/') + 1);
$file = $s3->get($name);
$headers = [
'Content-Type' => 'application/pdf',
'Content-Description' => 'File Transfer',
'Content-Disposition' => "attachment; filename={$name}",
'filename'=> $name
];
return response()->download($file);
}
i don't get it how to access the good file
response :
is_file() expects parameter 1 to be a valid path, string given
Any ideas ?
Your headers are not actually attached to the response. If you refer to: https://laravel.com/docs/5.5/responses#attaching-headers-to-responses you will see that the proper way to send headers in Laravel is:
return response($file)
->header('Content-Type', 'application/pdf')
->header('Content-Description', 'File Transfer')
->header('Content-Disposition', "attachment; filename={$name}")
->header('Filename', $name)
The $file is alse sent as a paramenter in reponse() instead of as download().
This is my code, it doesn't like the last line where I call a method from the header file. It claims invalid parameter number even though the method I'm calling takes the same amount of arguments. I don't understand the parameter was not defined part since $params is defined right before the call, and $query is passed a value from my other file, should I check if it's set? Here's my call to the uploadImage method with the value of $query:
Image::uploadImage('postimg', "UPDATE dry_posts SET postimg=:postimg WHERE id=:postid", array(':postid'=>$postid));
This file is supposed to upload images from a form in a another file onto imgur.
<?php
include_once("connect.php");
class Image
{
public static function uploadImage($formname,$query,$params)
{
$formname = "";
$response = "";
$image = "";
if(file_exists($formname))
{
$image = base64_encode(file_get_contents($_FILES[$formname]['tmp_name']));
}
$options = array('http'=>array(
'method'=>"POST",
'header'=>"Authorization: Bearer 8cd9d1bb71401737dc720f9381d8e9763f580af6\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))
{
$response = file_get_contents($imgurURL, false, $context);
}
$response = json_decode($response);
$preparams = array($formname=>$response->data->link);
$params = $preparams + $params;
connect::query($query,$params);
}
}
?>
In the array array(':postid'=>$postid), you also need to pass the param postimg which you have used in the query.
Something like array(':postid'=>$postid, ':postimg'=>$postimg)
I don't think you need the $formName array in the above statement
I'm trying to use this: Response::download() to make a download of a file, I'm using Laravel 4, here my code:
public function download_file($file)
{
$file = 'myfile.pdf';
//-- public/docs/myfile.pdf
$path = public_path(). '/docs/' . $file;
$headers = array(
'Content-Type' => 'application/pdf',
);
return Response::download($path, $file, $headers);
}
The error I got:
The file "C:\Users\myuser\Workbench\Web\sites\mysite\public/docs/myfile.pdf" does not exist
What did I went wrong?
Thanks!
I have this method:
protected function _sendRequest($url, $method, Busca_Cxense_Data $data, $get = null) {
if (! isset ( $this->_urls [$url] )) {
throw new Busca_Cxense_Exception_Argument ( "El tipo de url enviado no es valido. (type: {$url})" );
}
$url = $this->_urls [$url] . $data->getUrlKey () . ($get ? "$get" : '');
$httpConfig = array ('http' => array ('method' => $method, 'request_fulluri' => $url, 'ignore_errors' => false ) );
if ($data->getSendJson ()) {
$json = $this->_setJson ( $data );
$header = "Content-Type: application/json\r\nContent-Length: " . strlen ( $json );
$httpConfig ['http'] ['content'] = $json;
} else {
$header = "Content-Type: text/html";
}
$httpConfig ['http'] ['header'] = $header;
$context = stream_context_create ( $httpConfig );
$stream = fopen ($url, 'r', false, $context);
$result = stream_get_contents($stream);
$headers = stream_get_meta_data($stream);
fclose($stream);
if (! $result) {
print_r ( $data );
var_dump ( $url );
print_r ( $httpConfig );
throw new Busca_Cxense_Exception_MethodCall ( "Bad call. \nString: $json\n" );
}
var_dump($result); exit;
return array ('json' => json_decode ( $result ), 'string' => $result, 'headers' => $headers );
}
As you can see, it create a context and open an stream. However, I have a error very strange. If I send this url:
http://sandbox.cxsearch.cxense.com/api/search/levelup?p_aq=query%28category^1:%22preview%20trailer%22,token-op=or%29&p_sm=idobject:desc&p_s=0&p_c=20&p_dr=title
it throws a bad request error, but if I send this other one:
http://sandbox.cxsearch.cxense.com/api/search/levelup?p_q=test&p_sm=idobject:desc&p_s=0&p_c=20&p_dr=title
it works as expected. Do I have to encode the url or something?
FIXED
I was able to figure what the problem was. I Only need to change the space for %20. And that was all...
400 response is returned by remote server, so you want to see specs/contact people on that side on how to build correct query.
The urls you provide look very different and remote system might have own validation rules on values, list of provided parameters, etc. Also it might require some specific headers and/or request body.
I was able to figure what the problem was. I Only need to change the space for %20. And that was all...
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'),
));