Error: Call to a member function hashName() on null - php

Task: Upload image on s3 server
The code functioning properly on my local system and the file in saving properly on s3 server but when I push this code on server it gives me the hashName error.
Error: Call to a member function hashName() on null in file /var/www/html/doctring-api/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 240
Code for Image Helper
<?php
namespace App\Helpers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Facades\Image;
class UserHelper
{
public static function uploadImage($image)
{
try {
if (count(explode("data:image/", $image)) > 1) {
$fileName = \Carbon\Carbon::now()->timestamp . '_' . uniqid() . '.' . explode('/', explode(':', substr($image, 0, strpos($image, ';')))[1])[1];
$image = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '',$image));
Storage::disk('s3')->put($fileName, $image, 'public');
return $fileName;
}
return true;
} catch (\Exception $e) {
return false;
}
}
}
Api Controller
public function uploadPrescription(Request $request){
$validator = Validator::make($request->all(), [
'patient_id' => 'required',
'appointment_id' => 'required',
'prescription' => 'required'
]);
if($validator->fails()){
return $this->sendError('Validation Error.', $validator->errors());
}
$input = $request->all();
$status_check = Appointment::where('id','=',$input['appointment_id'])->first();
if($status_check->status == 'OnGoing'){
//upload prescription(image in base64) to s3 bucket
if($request->has('prescription'))
{
$imageName = UserHelper::uploadImage($request->prescription);
$input['image_url'] = $imageName;
}
$data=[
'patient_id' => $input['patient_id'],
'appointment_id' => $input['appointment_id'],
'prescription'=> $imageName
];
//Uploading Prescription only one record
// $profile = Prescriptions::updateOrCreate(Arr::except($data, 'prescription'), $data);
$profile = Prescriptions::updateOrCreate($data);
return response()->json(['message' => "Prescription Uploaded", 'profile'=> $profile, 'error'=> 0, 'status'=> 1 ]);
}else{
return response()->json(['message' => "Prescription Uploading Failed", 'error'=> 1, 'status'=> 0 ]);
}
}

At line 240 of Filesystem/FilesystemAdapter as reported by your error, there is this line:
return $this->putFileAs($path, $file, $file->hashName(), $options);
This means that $file is null when you are trying to upload it.
In your question you say that in local environment you don't have this problem, so you should check in the code that precede this, what is causing the problem on the production server environment.
Hope this helps

Related

Laravel API project how retrieve images from storage and send it to frontend

I am working on Laravel API project
I have destinations table and destination_images table with one-to-many relationship
When storing destination I am also receiving the images and store each image in Storage::disk('public') and generate random name for it and store the image name in the destination_images table
the store function
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:100',
'description' => 'nullable|string',
'fileSource' => 'required'
]);
if ($validator->fails()) {
$errors = $validator->errors();
return response()->json($errors);
}
$destination = Destination::create([
'name' => $request->name,
'description' => $request->description
]);
foreach ($request->fileSource as $img) {
$extension = explode('/', explode(':', substr($img, 0, strpos($img, ';')))[1])[1];
$replace = substr($img, 0, strpos($img, ',')+1);
$image = str_replace($replace, '', $img);
$image = str_replace(' ', '+', $image);
$imageName = 'destination-' . Str::random(10).'.'.$extension;
Storage::disk('public')->put($imageName, base64_decode($image));
DestinationImage::create([
'destination_id' => $destination->id,
'img' => $imageName
]);
}
return response()->json('Destination Created Successfully');
}
My question is how to handle the show function? Should I use the image name I am getting from the database with a link in the frontend? What is the best practice for this process?
Laravel can automatically include your relationships. So when you show the Destination just include it. Notice i'm using model binding for the Destination.
public function show(Destianation $destination) {
$destination->load('destinationImage'); // load the relationship.
return $destination;
}
class DestinationImage {
protected $appends = [
'path',
];
public function getPathAttribute()
{
return Storage::disk('public')->path($this->img);
}
}
Now your response should look like this.
{
... // fields
destinationImages: [{
img: "somename.jpg",
}];
}
This is not enough to show the image, Laravel storage has a method called path, to get the full path of the image. Now you need to make an Eloquent Getter and append it to the DestinationImage model. This will automatically add it to your response.
class DestinationImage {
protected $appends = [
'path',
];
public function getPathAttribute()
{
return Storage::disk('public')->url($this->img);
}
}

Trying to Get the name of an uploaded Image

I am trying to get the name of an image and save it instead of saving it as laravel default hashing.
i.e if an image name is go.jpg it should save as go.jpg instead of randomly generated numbers
Here is my controller
private function storeImage($news)
{
if (request()->has('image')){
$news->update([
'image' => request()->image->store('uploads', 'public'),
]);
$image = Image::make(public_path('storage/'. $news->image))->resize(600, 600);
$image->save();
}
}
You can use this method: getClientOriginalName()
if ($request->hasFile('image')) {
return $request->file('image')->getClientOriginalName();
} else {
return 'no file!'
}
http://api.symfony.com/3.0/Symfony/Component/HttpFoundation/File/UploadedFile.html#method_getClientOriginalName
getClientOriginalName use this method.
use Illuminate\Support\Facades\Input;
private function storeImage($news)
{
if (request()->has('image')){
$file = Input::file('image');
$img= $file->getClientOriginalName().'.'.$file->getClientOriginalExtension();
$news->update([
'image' => $img,
]);
$image = Image::make(public_path('storage/'. $news->image))-
>resize(600, 600);
$image->save();
}
}

Laravel Video, Audio and image upload

This is my image upload method of PostsController
public function store(Request $request, User $user, Image $image)
{
$this->validate($request, [
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
'body' => 'required'
]);
if( $request->hasFile('image') ) {
$image = $request->file('image');
$filename = time() . '.' . $image->getClientOriginalExtension();
Image::make($image)->save( public_path('uploads/images/' . $filename ) );
}
$image = $filename;
auth()->user()->publish(
new Post(['body' => request('body'), 'image' => $image, 'user_id' => auth()->id()])
);
return redirect('/');
}
I want one method to upload image, video and audio as well with one input that user can upload image or video or audio
How can i do all these things in one controller?
First determine the whether the file is a video, audio or image. Then decide how you validate. Hope this will help.
if( $request->hasFile('file') ) {
$file = $request->file('file');
$imagemimes = ['image/png']; //Add more mimes that you want to support
$videomimes = ['video/mp4']; //Add more mimes that you want to support
$audiomimes = ['audio/mpeg']; //Add more mimes that you want to support
if(in_array($file->getMimeType() ,$imagemimes)) {
$filevalidate = 'required|mimes:jpeg|max:2048';
}
//Validate video
if (in_array($file->getMimeType() ,$videomimes)) {
$filevalidate = 'required|mimes:mp4';
}
//validate audio
if (in_array($file->getMimeType() ,$audiomimes)) {
$filevalidate = 'required|mimes:mpeng';
}
}
$this->validate($request, [
'file' => $filevalidate,
'body' => 'required'
]);
If you are using form requests, try with below code
public function rules() {
$rules = [
'some_field' => 'required',
];
// if fileType is audio
if ($this->input('fileType') == 'audio') {
$rules['file'] = 'mimes:mp3,mp4';
}
//if fileType is video
if ($this->input('fileType') == 'video') {
$rules['file'] = 'mimes:mp4,3gp';
}
return $rules;
}
field names and validation rules change as per your requirement.

Laravel 5 Validation in controller

I have 2 methods in my Controller and I need to validate it but I don't know how.
1st method which should allow all image extensions:
public function testing(Request $request) {
if($request->hasFile('img')) {
$image = Input::file('img');
$filename = time() . '.' . $image->getClientOriginalExtension();
$path = public_path('images/' . $filename);
Image::make($image->getRealPath())->resize(200, 200)->save($path);
$file = $request->file('img');
return ['url' => url('images/' . $filename)];
}
}
2nd method which should only allow 1 word and if there is space, trim it into 1 word:
public function postDB(Request $request) {
$newName = $request->input('newName');
$websites = new Website();
$websites->name = $newName;
$websites->save();
return redirect('template')->with('status', 'Website has been saved successfully!');
}
First write new Request for your data
php artisan make:request ImageRequest
Than write in ImageRequest:
public function authorize()
{
return true;
}
public function rules()
{
return [
'img' => 'file|image',
]
}
If you want to customize error messages:
public function messages()
{
return [
'img.image' => 'Some custom message ...',
];
}
Last inject request to your method (don`t forget about use App\Http\Requests):
public function testing(Requests\ImageRequest $request) {
//for retrieving validation errors use:
$imgErrors = $errors->first('img');
}
More information about Form Request Validation
Or you can use Validator facade (don`t forget about use Validator):
$validator = Validator::make(
$image, [
'img' => 'file|image',
]
);
More information about A Note On Optional Fields

cakePHP 3.0 uploading images

I want to upload images in my cakephp 3.0 app. But I get the error message:
Notice (8): Undefined index: Images [APP/Controller/ImagesController.php, line 55]
Are there already some examples for uploading files (multiple files at once) in cakePHP 3.0? Because I can only find examples for cakePHP 2.x !
I think I need to add a custom validation method in my ImagesTable.php? But I can't get it to work.
ImagesTable
public function initialize(array $config) {
$validator
->requirePresence('image_path', 'create')
->notEmpty('image_path')
->add('processImageUpload', 'custom', [
'rule' => 'processImageUpload'
])
}
public function processImageUpload($check = array()) {
if(!is_uploaded_file($check['image_path']['tmp_name'])){
return FALSE;
}
if (!move_uploaded_file($check['image_path']['tmp_name'], WWW_ROOT . 'img' . DS . 'images' . DS . $check['image_path']['name'])){
return FALSE;
}
$this->data[$this->alias]['image_path'] = 'images' . DS . $check['image_path']['name'];
return TRUE;
}
ImagesController
public function add()
{
$image = $this->Images->newEntity();
if ($this->request->is('post')) {
$image = $this->Images->patchEntity($image, $this->request->data);
$data = $this->request->data['Images'];
//var_dump($this->request->data);
if(!$data['image_path']['name']){
unset($data['image_path']);
}
// var_dump($this->request->data);
if ($this->Images->save($image)) {
$this->Flash->success('The image has been saved.');
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error('The image could not be saved. Please, try again.');
}
}
$images = $this->Images->Images->find('list', ['limit' => 200]);
$projects = $this->Images->Projects->find('list', ['limit' => 200]);
$this->set(compact('image', 'images', 'projects'));
$this->set('_serialize', ['image']);
}
Image add.ctp
<?php
echo $this->Form->input('image_path', [
'label' => 'Image',
'type' => 'file'
]
);
?>
Image Entity
protected $_accessible = [
'image_path' => true,
];
In your view file, add like this, in my case Users/dashboard.ctp
<div class="ChImg">
<?php
echo $this->Form->create($particularRecord, ['enctype' => 'multipart/form-data']);
echo $this->Form->input('upload', ['type' => 'file']);
echo $this->Form->button('Update Details', ['class' => 'btn btn-lg btn-success1 btn-block padding-t-b-15']);
echo $this->Form->end();
?>
</div>
In your controller add like this, In my case UsersController
if (!empty($this->request->data)) {
if (!empty($this->request->data['upload']['name'])) {
$file = $this->request->data['upload']; //put the data into a var for easy use
$ext = substr(strtolower(strrchr($file['name'], '.')), 1); //get the extension
$arr_ext = array('jpg', 'jpeg', 'gif'); //set allowed extensions
$setNewFileName = time() . "_" . rand(000000, 999999);
//only process if the extension is valid
if (in_array($ext, $arr_ext)) {
//do the actual uploading of the file. First arg is the tmp name, second arg is
//where we are putting it
move_uploaded_file($file['tmp_name'], WWW_ROOT . '/upload/avatar/' . $setNewFileName . '.' . $ext);
//prepare the filename for database entry
$imageFileName = $setNewFileName . '.' . $ext;
}
}
$getFormvalue = $this->Users->patchEntity($particularRecord, $this->request->data);
if (!empty($this->request->data['upload']['name'])) {
$getFormvalue->avatar = $imageFileName;
}
if ($this->Users->save($getFormvalue)) {
$this->Flash->success('Your profile has been sucessfully updated.');
return $this->redirect(['controller' => 'Users', 'action' => 'dashboard']);
} else {
$this->Flash->error('Records not be saved. Please, try again.');
}
}
Before using this, create a folder in webroot named upload/avatar.
Note: The input('Name Here'), is used in
$this->request->data['upload']['name']
you can print it if you want to see the array result.
Its works like a charm in CakePHP 3.x
Now that everyone makes advertisement for his plugins here, let me do this as well. I've checked the Uploadable behavior linked in the other question, it's pretty simple and half done it seems.
If you want a complete solution that is made to scale on enterprise level check FileStorage out. It has some features I haven't seen in any other implementations yet like taking care of ensuring your won't run into file system limitations in the case you get really many files. It works together with Imagine to process the images. You can use each alone or in combination, this follows SoC.
It is completely event based, you can change everything by implementing your own event listeners. It will require some intermediate level of experience with CakePHP.
There is a quick start guide to see how easy it is to implement it. The following code is taken from it, it's a complete example, please see the quick start guide, it's more detailed.
class Products extends Table {
public function initialize() {
parent::initialize();
$this->hasMany('Images', [
'className' => 'ProductImages',
'foreignKey' => 'foreign_key',
'conditions' => [
'Documents.model' => 'ProductImage'
]
]);
$this->hasMany('Documents', [
'className' => 'FileStorage.FileStorage',
'foreignKey' => 'foreign_key',
'conditions' => [
'Documents.model' => 'ProductDocument'
]
]);
}
}
class ProductsController extends ApController {
// Upload an image
public function upload($productId = null) {
if (!$this->request->is('get')) {
if ($this->Products->Images->upload($productId, $this->request->data)) {
$this->Session->set(__('Upload successful!');
}
}
}
}
class ProductImagesTable extends ImageStorageTable {
public function uploadImage($productId, $data) {
$data['adapter'] = 'Local';
$data['model'] = 'ProductImage',
$data['foreign_key'] = $productId;
$entity = $this->newEntity($data);
return $this->save($data);
}
public function uploadDocument($productId, $data) {
$data['adapter'] = 'Local';
$data['model'] = 'ProductDocument',
$data['foreign_key'] = $productId;
$entity = $this->newEntity($data);
return $this->save($data);
}
}
Maybe the following would help. It's a behavior who helps you to upload files very easy!
http://cakemanager.org/docs/utils/1.0/behaviors/uploadable/
Let me know if you struggle.
Greetz
/*Path to Images folder*/
$dir = WWW_ROOT . 'img' .DS. 'thumbnail';
/*Explode the name and ext*/
$f = explode('.',$data['image']['name']);
$ext = '.'.end($f);
/*Generate a Name in my case i use ID & slug*/
$filename = strtolower($id."-".$slug);
/*Associate the name to the extension */
$image = $filename.$ext;
/*Initialize you object and update you table in my case videos*/
$Videos->image = $image;
if ($this->Videos->save($Videos)) {
/*Save image in the thumbnail folders and replace if exist */
move_uploaded_file($data['image']['tmp_name'],$dir.DS.$filename.'_o'.$ext);
unlink($dir.DS.$filename.'_o'.$ext);
}
<?php
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Controller\ComponentRegistry;
use Cake\Network\Exception\InternalErrorException;
use Cake\Utility\Text;
/**
* Upload component
*/
class UploadRegCompanyComponent extends Component
{
public $max_files = 1;
public function send( $data )
{
if ( !empty( $data ) )
{
if ( count( $data ) > $this->max_files )
{
throw new InternalErrorException("Error Processing Request. Max number files accepted is {$this->max_files}", 1);
}
foreach ($data as $file)
{
$filename = $file['name'];
$file_tmp_name = $file['tmp_name'];
$dir = WWW_ROOT.'img'.DS.'uploads/reg_companies';
$allowed = array('png', 'jpg', 'jpeg');
if ( !in_array( substr( strrchr( $filename , '.') , 1 ) , $allowed) )
{
throw new InternalErrorException("Error Processing Request.", 1);
}
elseif( is_uploaded_file( $file_tmp_name ) )
{
move_uploaded_file($file_tmp_name, $dir.DS.Text::uuid().'-'.$filename);
}
}
}
}
}
We're using https://github.com/josegonzalez/cakephp-upload with great success in our production app, and has done so for quite some time.
Has awesome support for using "Flysystem" (https://flysystem.thephpleague.com/) as well - which is abstractions from specific file system(s) - so moving from normal local file system to S3 is a no-brainer, or Dropbox or whatever place you want :-)
You can find related (high quality) plugins on file uploading right here: https://github.com/FriendsOfCake/awesome-cakephp#files - I've used "Proffer" with success as well, and it's by no means "almost done" or anything alike - both has all my recommendations and is in my eyes production ready!

Categories