I´m trying to upload an image from my server to another one using an API.
I´ve uploaded to my server using native Storage facade and then, call the Guzzle function to upload the file to the other server.
The problem is that I can´t get the local of the file. Let´s see some code:
public function saveImage(Request $request)
{
// return $request;
$consorciado = Consorciado::where('id', '=', $request->consorciado_id)->first();
$documento = Documento::where('doc_id', '=', $request->id)->first();
$documento = new Documento();
$image = request()->file('f');
$documento->consorciado_id = $consorciado->id;
$documento->doc_id = $request->id;
$documento->tipo = $request->tipo;
$documento->remark = $request->remark;
$documento->idTematica = $request->idTematica;
$documento->field1 = $request->field1;
$documento->field2 = $request->field2;
$documento->field3 = $request->field3;
$documento->field4 = $request->field4;
$documento->field5 = $request->field5;
$filename = $consorciado->id . "_" . $documento->doc_id . "." . $image->getClientOriginalExtension();
$documento->nome = $filename;
// dd($doc);
// $file = fopen(Storage::disk('local') . '/' . file_get_contents($image), 'r');
// dd($file);
$client = new Client([
'base_uri' => 'http://gedocflex.com.br:8003/api/file',
]);
$response = $client->request('POST', 'http://gedocflex.com.br:8003/api/file', [
'multipart' => [
[
'name' => 'idTematica',
'contents' => '201'
],
[
'name' => 'f',
// 'contents' => $filename, file_get_contents($image)
'contents' => fopen('/' . $filename, file_get_contents($image), 'w+')
],
[
'name' => 'field1',
'contents' => '132.626.688-85'
],
[
'name' => 'field2',
'contents' => '7758'
],
[
'name' => 'field3',
'contents' => '404'
],
[
'name' => 'field4',
'contents' => '0'
],
[
'name' => 'field5',
'contents' => 'Marcello Dantas Correia'
],
[
'name' => 'remark',
'contents' => 'Enviando do meu servidor para o GED'
],
]
]);
return $response;
Storage::disk('local')->put('public/' . $filename, file_get_contents($image), 'public');
$documento->save(); //salva no meu banco
}
I´m using php artisan storage:link and the error is:
{message: "fopen(/1_1.jpeg): failed to open stream: No such file or directory",…}
exception: "ErrorException"
file: "/Users/marcellopato/Sites/contemplado/app/Http/Controllers/DocumentoController.php"
line: 234
message: "fopen(/1_1.jpeg): failed to open stream: No such file or directory"
trace: [{function: "handleError", class: "Illuminate\Foundation\Bootstrap\HandleExceptions", type: "->"},…]
As you can see, I get the name of the file, but not its path.
What I am doing wrong?
Anyone?
Thanks in advance!
Related
Hi I am trying to send an image. The documentation states that I can send a file using multipart/form-data.
Here is my code:
// I checked it, there really is a file.
$file = File::get(Storage::disk('local')->path('test.jpeg')) // it's the same as file_get_contents();
// Here I use the longman/telegram-bot library.
$serverResponse = Request::sendPhoto([
'chat_id' => $this->tg_user_chat_id,
'photo' => $file
]);
// Here I use Guzzle because I thought that there might be an
// error due to the longman/telegram-bot library.
$client = new Client();
$response = $client->post("https://api.telegram.org/$telegram->botToken/sendPhoto", [
'multipart' => [
[
'name' => 'photo',
'contents' => $file
],
[
'name' => 'chat_id',
'contents' => $this->tg_user_chat_id
]
]
]);
Log::info('_response', ['_' => $response->getBody()]);
Log::info(env('APP_URL') . "/storage/$url");
Log::info('response:', ['_' => $serverResponse->getResult()]);
Log::info('ok:', ['_' => $serverResponse->getOk()]);
Log::info('error_code:', ['_' => $serverResponse->getErrorCode()]);
Log::info('raw_data:', ['_' => $serverResponse->getRawData()]);
In both cases, I get this response:
{\"ok\":false,\"error_code\":400,\"description\":\"Bad Request: invalid file HTTP URL specified: Wrong URL host\"}
Other download methods (by ID and by link) work. Can anyone please point me in the right direction?
Using the php-telegram-bot
library, sendPhoto can be used like so:
<?php
require __DIR__ . '/vendor/autoload.php';
use Longman\TelegramBot\Telegram;
use Longman\TelegramBot\Request;
// File
$file = Request::encodeFile('/tmp/image.jpeg');
// Bot
$key = '859163076:something';
$telegram = new Telegram($key);
// sendPhoto
$chatId = 000001;
$serverResponse = Request::sendPhoto([
'chat_id' => $chatId,
'photo' => $file
]);
The trick is to use Request::encodeFile to read the local image.
I am implementing S3 file uploads and downloads using pre-signed urls. I have one s3 bucket (versioning enabled) and one AWS user but I want to track the history of each file in terms of which of my application users modified the file.
I have a versioned S3 bucket and my thought is that I can append metadata to every file to identify my application user and possibly other data too.
Here is my code:
public function presignedUpload(Request $request)
{
$this->validate($request, [
'name' => 'string|required'
]);
$s3 = Storage::disk('s3');
$client = $s3->getDriver()->getAdapter()->getClient();
$expiry = "+10 minutes";
$options = ['user-data' => 'user-meta-value'];
$cmd = $client->getCommand('PutObject', [
'Bucket' => \Config::get('filesystems.disks.s3.bucket'),
'Key' => 'path/to/file/' . $request->name,
'ACL' => 'public-read',
], $options);
$request = $client->createPresignedRequest($cmd, $expiry);
$presignedUrl = (string)$request->getUri();
return response()->json(['url' => $presignedUrl], 201);
}
I deduced that I can pass an $options array from the FilesystemAdapter::class. This code does upload the file, but the metadata in AWS looks empty.
Is my $options array in the wrong format?
Appreciate any help on this.
The selected answer doesn't work anymore after Laravel 9. Flysystem recommends you to use S3 SDK instead of Storage driver.
https://github.com/thephpleague/flysystem/issues/1423
Use the S3 SDK instead to create a resigned upload URL.
$uploadDisk = 's3';
$s3Client = new S3Client([
'credentials' => [
'key' => config('filesystems.disks.' . $uploadDisk . '.key'),
'secret' => config('filesystems.disks.' . $uploadDisk . '.secret'),
],
'region' => config('filesystems.disks.' . $uploadDisk . '.region'),
'version' => 'latest',
]);
$s3Bucket = config('filesystems.disks.' . $uploadDisk . '.bucket');
$s3Key = \Illuminate\Support\Str::uuid(); // your file name
$s3Options = [];
$command = $s3Client->getCommand('PutObject', [
'Bucket' => $s3Bucket,
'Key' => $s3Key,
'MetaData' => $s3Options,
]);
$request = $s3Client->createPresignedRequest($command, '+20 minutes');
$url = (string) $request->getUri();
Metadata can be uploaded like this:
public function presignedUpload(Request $request)
{
$this->validate($request, [
'name' => 'string|required'
]);
$s3 = Storage::disk('s3');
$client = $s3->getDriver()->getAdapter()->getClient();
$expiry = "+10 minutes";
$options = ['user-data' => 'user-meta-value'];
$cmd = $client->getCommand('PutObject', [
'Bucket' => \Config::get('filesystems.disks.s3.bucket'),
'Key' => 'path/to/file/' . $request->name,
'ACL' => 'public-read',
'Metadata' => $options,
]);
$request = $client->createPresignedRequest($cmd, $expiry);
$presignedUrl = (string)$request->getUri();
return response()->json(['url' => $presignedUrl], 201);
}
I want to send a random photo in TelegramBot, I wrote this code, but it doesn't work. How do I solve this problem?
Code:
$pictures = [
[
"file"=>"data/pictures/pic1.jpg",
],
[
"file"=>"data/pictures/pic2.jpg",
]
];
$random_image = $pictures[rand(0, count($pictures) - 1)];
if ($text == "pictest"){
Bot('SendPhoto',[
'chat_id' => $chat_id,
'photo' => $random_image,
]);
}
Here, we might be missing:
a base domain before images, such as: domain.org/data/pictures/pic1.jpg
or the file index in $random_image
$pictures = [
[
"file" => "data/pictures/pic1.jpg",
],
[
"file" => "data/pictures/pic2.jpg",
],
];
$random_image = $pictures[rand(0, count($pictures) - 1)]["file"];
if ($text == "pictest"){
Bot('SendPhoto',[
'chat_id' => $chat_id,
'photo' => $random_image,
]);
}
I am uploading files to S3 :
In file system i have :
'default' => 's3',
'cloud' => 's3',
's3' => [
'driver' => 's3',
'key' => '***********',
'secret' => '********************',
'region' => '************',
'bucket' => '*************',
],
],
'parent_url' => 'http://54.169.67.54/',
];
Everything seems fine but error comes up when upload a file.
fopen(/var/www/html/project/public/photos/profile-pics/1-medium-1470892864.jpg): failed to open stream: Permission denied
use League\Flysystem and check this for further reference
Example :
public function uploadFile( $getFile )
{
try{
$datetimefilename = Carbon::now()->format('YmdHis');
$ext = $getFile->getClientOriginalExtension();
$filename = sprintf('%s.%s', $datetimefilename,$ext);
$uploadPath = env('UPLOAD');
if( Storage::disk('s3')->has($uploadPath) === false ){
Storage::disk('s3')->createDir($uploadPath);
}
$filePath = sprintf('%s/%s',$uploadPath,$filename);
$result = Storage::disk('s3')->put($filePath, file_get_contents($getFile->getRealPath()));
return $result ;
}
catch(\Exception $e)
{
return false;
}
}
I am able to upload a file to an API endpoint using Postman.
I am trying to translate that into uploading a file from a form, uploading it using Laravel and posting to the endpoint using Guzzle 6.
Screenshot of how it looks in Postman (I purposely left out the POST URL)
Below is the text it generates when you click the "Generate Code" link in POSTMAN:
POST /api/file-submissions HTTP/1.1
Host: strippedhostname.com
Authorization: Basic 340r9iu34ontoeioir
Cache-Control: no-cache
Postman-Token: 6e0c3123-c07c-ce54-8ba1-0a1a402b53f1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="FileContents"; filename=""
Content-Type:
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="FileInfo"
{ "name": "_aaaa.txt", "clientNumber": "102425", "type": "Writeoff" }
----WebKitFormBoundary7MA4YWxkTrZu0gW
Below is controller function for saving the file and other info. The file uploads correctly, I am able to get the file info.
I think the problem I am having is setting the multipart and headers array with the correct data.
public function fileUploadPost(Request $request)
{
$data_posted = $request->input();
$endpoint = "/file-submissions";
$response = array();
$file = $request->file('filename');
$name = time() . '_' . $file->getClientOriginalName();
$path = base_path() .'/public_html/documents/';
$resource = fopen($file,"r") or die("File upload Problems");
$file->move($path, $name);
// { "name": "test_upload.txt", "clientNumber": "102425", "type": "Writeoff" }
$fileinfo = array(
'name' => $name,
'clientNumber' => "102425",
'type' => 'Writeoff',
);
$client = new \GuzzleHttp\Client();
$res = $client->request('POST', $this->base_api . $endpoint, [
'auth' => [env('API_USERNAME'), env('API_PASSWORD')],
'multipart' => [
[
'name' => $name,
'FileContents' => fopen($path . $name, 'r'),
'contents' => fopen($path . $name, 'r'),
'FileInfo' => json_encode($fileinfo),
'headers' => [
'Content-Type' => 'text/plain',
'Content-Disposition' => 'form-data; name="FileContents"; filename="'. $name .'"',
],
// 'contents' => $resource,
]
],
]);
if($res->getStatusCode() != 200) exit("Something happened, could not retrieve data");
$response = json_decode($res->getBody());
var_dump($response);
exit();
}
The error I am receiving, screenshot of how it displays using Laravel's debugging view:
The way you are POSTing data is wrong, hence received data is malformed.
Guzzle docs:
The value of multipart is an array of associative arrays, each
containing the following key value pairs:
name: (string, required) the form field name
contents:(StreamInterface/resource/string, required) The data to use in the
form element.
headers: (array) Optional associative array of custom headers to use with the form element.
filename: (string) Optional
string to send as the filename in the part.
Using keys out of above list and setting unnecessary headers without separating each field into one array will result in making a bad request.
$res = $client->request('POST', $this->base_api . $endpoint, [
'auth' => [ env('API_USERNAME'), env('API_PASSWORD') ],
'multipart' => [
[
'name' => 'FileContents',
'contents' => file_get_contents($path . $name),
'filename' => $name
],
[
'name' => 'FileInfo',
'contents' => json_encode($fileinfo)
]
],
]);
$body = fopen('/path/to/file', 'r');
$r = $client->request('POST', 'http://httpbin.org/post', ['body' => $body]);
http://docs.guzzlephp.org/en/latest/quickstart.html?highlight=file
In Laravel 8 with guzzle I am using this:
The idea is that you are reading the file with fread or file_get_content, then you can use the Laravel getPathname() which points to the file in /tmp
$response = $this
->apiClient
->setUserKey($userToken)
->post(
'/some/url/to/api',
[
'multipart' => [
'name' => 'avatar',
'contents' => file_get_contents($request->file('avatar')->getPathname()),
'filename' => 'avata.' . $request->file('avatar')->getClientOriginalExtension()
]
]
);