Store the original name of an image that was sent in a form

1

You see, I'm creating a form to store the data of a plant, in which you have to capture an image. The code is this:

@extends('layouts.app')
@section('content')

@Logged()
@include('partials.errors')
<div align="center" class="panel panel-default">
    <h1 class="text-center text-mute"> {{ __("Nueva Planta") }} </h1>
</div>
<div class="row">
    <form method="POST" action="../planta" enctype="multipart/form-data">
        {{ csrf_field() }}
        <div class="form-group">
            <label for="nombre" class="col-md-12 control-label"> {{ __("Nombre") }}
            </label>
            <input id="nombre" class="form-control" name="nombre" value="{{ old('nombre') }}"/>
        </div>

        <div class="form-group">
            <label for="tamaño" class="col-md-12 control-label"> {{ __("Tamaño") }}
            </label>
            <input id="tamaño" class="form-control" name="tamaño" value="{{ old('tamaño') }}"/>
        </div>

        <div class="form-group">
            <label for="flor" class="col-md-12 control-label"> {{ __("Flor") }}
            </label>
            <input id="flor" class="form-control" name="flor" value="{{ old('flor') }}"/>
        </div>

        <div class="form-group">
            <label for="hoja" class="col-md-12 control-label"> {{ __("Hoja") }}
            </label>
            <input id="hoja" class="form-control" name="hoja" value="{{ old('hoja') }}"/>
        </div>

        <div class="form-group">
            <label for="descripcion" class="col-md-12 control-label"> {{ __("Descripción") }}
            </label>
            <input id="descripcion" class="form-control" name="descripcion" value="{{ old('descripcion') }}"/>
        </div>

        <label class="btn btn-warning" for="foto">
            <input id="foto" name="foto" type="file" style="display:none;"> {{ __("Subir imagen (Opcional)") }}
        </label>

        <button type="submit" name="addPlanta" class="btn btn-default"> {{ __("Añadir Planta") }}
        </button>
    </form>
</div>
@else
    <h1 class="text-center text-mute" style="color:#FF0000"> {{ __("Insistimos, ¡INICIA SESIÓN SI QUIERES INTRODUCIR NUEVAS PLANTAS!") }} </h1>
@endLogged
@endsection

But the story is that I run the form, I'm going to phpMyAdmin to see the new plant and I got everything with this:

And ovbiamente this is anything but successful. In fact, I modify the variable cited by girasol.jpg (which is in public) and I find that now if you see the image.

How do I fix this? Apart, I'm calling images stored in public, but I will not always have the image stored right there, so one of 2, or I get the image to be searched from an absolute path or in case it has not imported from the directory public the image that generates a copy of the image in that directory (and I see this last recommended).

And true, the view I use:

@extends('layouts.app')
@section('content')
<div class="row">
    <div class="col-md-8 col-md-offset-2">
        <div align="center" class="panel panel-default">
            <div class="panel-heading">
                <h1 class="text-center text-mute"> {{ __("Plantas") }} </h1>
            </div>
            <div class="panel-body">
                @Logged()
                    <a href="formulario/plantas">Crear una nueva planta</a>
                    @include('partials.errors')
                @else
                    <p style="color:#0000FF">Para poner insertar nuevas plantas tienes que iniciar sesión</p>
                @endLogged
            </div>
        </div>
        @forelse($planta as $plantas)
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3><a href="comentarios/{{ $plantas->id }}">{{ $plantas->nombre }}</a></h3>
            </div>
            <div class="panel-body">
                <h4>{{ $plantas->descripcion }}</h4>
                @if(empty($plantas->foto)==false)
                    <img src="{{ $plantas->foto }}" style="width: 200px; height: 200px; border: 2px solid green" class="img-responsive img-rounded" >
                @endif
            </div>
            <div class="panel-body">
                <b>Tamaño:</b> {{ $plantas->tamaño }}<br>
                <b>Flor:</b> {{ $plantas->flor }}<br>
                <b>Hoja:</b> {{ $plantas->hoja }}<br>
                <span class="pull-right"> {{ __("Comentarios") }}: {{ $plantas->comentarios->count() }} </span>
            </div>
        </div>
        @empty
        <div class="alert alert-danger">
            {{ __("No hay ninguna planta en este momento") }}
        </div>
        @endforelse
        @if($planta->count())
        {{$planta->links()}}
        @endif
    </div>
</div>
@endsection

Edit: I expand the information to show more data.

filesystems.php:

 'planta' => [
            'driver' => 'local',
            'root' => storage_path('public\images\planta'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
        ],

web.php:

Route::get('/images/{path}/{attachment}', function ($path, $attachment){
    $storagePath = Storage::disk($path)->getDriver()->getAdapter()->getPathPrefix();
    $imageFilePath = $storagePath . $attachment;
    if(File::exists($imageFilePath)){
        return Image::make($imageFilePath)->response();
    }
});

plantas.php:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class plantas extends Model{
    protected $table = 'plantas';

    protected $fillable = [
        'nombre', 'tamaño', 'flor', 'hoja', 'descripcion', 'foto',
    ];

    public function comentarios(){
        return $this->hasMany(Comentario::class,'planta');
    }

    public function pathAttachment(){
        return "/images/planta/" . $this->attachment;
    }
}

Edit: Try removing the fragment of the form for the image style="display: none;"

As seen in the image, the form can see the name of the image. If when this variable is stored in my phpMyAdmin database keep the name with which it shows, I would have all this solved, but guess what ...

Something goes wrong and is stored under another name.

Another thing, in the store () function of plantsController.php I tried to put this:

dd($request->foto);

Which produces the following result:

If I could somehow make what is in the underlined variable what the database stored, I would solve this. In fact, the function with which the original name is obtained is $ request- > foto-> gtClientOriginalName (), although it is information that tends to be lost after making the form.

    
asked by Miguel Alparez 14.02.2018 в 21:46
source

2 answers

2

I will indicate the whole process of how to upload an image and then show it with Laravel 5.1 . I think it did not change anything in later versions, just in case, the part that seems that you do not know how to do right now, is to save the image in the server from the temporary file and get the route, I indicate it in pure PHP, which is the simplest. To see how it works you can try this in a clean installation of Laravel .

1. Routes.

I create three routes, one to show a form, another to send / process it and a third to show the newly loaded image.

//Ver formulario
Route::get('imagen', function () {
    return view('form-imagen');
});

//Procesar formulario
Route::post('imagen',
    [
        'as'    => 'imagen',
        'uses'  => 'ImagenController@store'
    ]
);

//Ver imagen subida
Route::get('show-imagen', function () {
    return view('show-imagen');
});

2. Views.

  • Simplified form, based on yours, only with the name field and the loading input of the image.

        

        <h1>Formulario de carga de imagen</h1>
    
        <div class="row">
        <form method="POST"
            action="{{ route('imagen') }}"
            enctype="multipart/form-data">
    
            {{ csrf_field() }}
    
            <div class="form-group">
                <label for="nombre" class="col-md-12 control-label">Nombre</label>
                <input id="nombre" class="form-control" name="nombre" value="nombre"/>
            </div>
    
            <input type="hidden" name="MAX_FILE_SIZE" value="1000000" />
            <!-- Se recomienda usar el campo anterior en el formulario.
            Ver documentación de PHP:
            http://php.net/manual/es/features.file-upload.post-method.php -->
    
            <label class="btn btn-warning" for="foto">
            <input id="foto"
                name="foto"
                type="file"
                style="display:none;">Cargar imagen (Opcional)</label>
    
            <button type="submit"
                class="btn btn-default">Enviar imagen</button>
        </form>
    </div>
    

  • In the head would load the bootstrap:

    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css">
        <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script>
    
  • View that only shows the data loaded with the previous form and a link to it to reload another image.

    <body>
        <div class="wrap">
            <h1>Vista de imagen</h1>
    
            @if (session('data'))
                <p>Se reciben datos...</p>
                {{-- var_dump(session('data')) --}}
    
    
    
                <p>Imagen cargada: {{ session('data')['name'] }}</p>
                <img src="{{ asset( session('data')['path'] ) }}" alt="imagen">
            @else
                <p>No se reciben datos...</p>
                {!! var_dump(session('data')) !!}
            @endif
    
            <p><a href="{{ url('/imagen') }}">Cargar imagen</a></p>
        </div>
    </body>
    
  • 3. Controller

    I will use pure PHP to save the image in the public folder, inside images , that is, in "public / images /". I have not validated it, just stored and loaded the route in the data that happened to the view that proves that the image has been uploaded. It can be validated with PHP with the data shown when debugging $ _ FILES or with Laravel methods, in any case the usual would be: weight of the image (which is within limits) and format, for example if only jpeg and png are allowed.

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use App\Http\Requests;
    use App\Http\Controllers\Controller;
    
    
    class ImagenController extends Controller
    {
    
        /**
         * Store a newly created resource in storage.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return \Illuminate\Http\Response
         */
        public function store(Request $request)
        {
            //información de depuración (uso raw PHP)
            print_r($_REQUEST); echo('<br>');
            print_r($_FILES);   echo('<hr>');
    
            /**
             * Procesando imagen
             *
             */
            if (isset($_FILES['foto'])) {
    
                if (isset($_REQUEST['nombre'])) {
                    $name = $_REQUEST['nombre'];
                } else {
                    $name = basename($_FILES['uploadedfile']['name']);
                }
    
                $target_path = 'imagenes/';
                $target_path = $target_path . basename($_FILES['foto']['name']);
                if (move_uploaded_file($_FILES['foto']['tmp_name'], $target_path)) {
                    return self::processPath($target_path, $name);
                } else {
                    echo('ERR -> Fallo carga de imagen.');
                }
            } else {
                echo('ERR -> No se envío imagen.');
            }
        }
    
    
        private static function processPath(String $path, String $name)
        {
    
            //dd('Ruta imagen: ' . $path);
    
            /**
             * Aquí se persiste la ruta al fichero en BD, fichero, etc.
             * Para el ejemplo sólo voy a pasar los datos a la vista para
             * comprobar que se ha subida la imagen y se encuentra disponible
             *
             */
    
            $arr_data = [
                'name' => $name,
                'path' => $path,
            ];
    
            return redirect('show-imagen')
                ->with('data', $arr_data);
        }
    
    } //class
    

    Note: If the image does not load, one possibility is to exceed the size of MAX_FILE_SIZE that I have included in the form.

    And this is it. To have a complete system, it would be necessary to persist the route where we keep the image and then recover it to show it from this one.

        
    answered by 18.02.2018 / 22:51
    source
    2

    To start, you have to modify the store () method of plantas.php:

    public function store(Request $request){
            $normas=[
                'nombre' => 'required|max:100|unique:plantas',
                'descripcion' => 'required|max:200',
                'foto' => 'image',
            ];
    
            $this->validate($request,$normas);
    
            $real=$request->foto->getClientOriginalName();
    
            Plantas::create(['id'=>$request->id, 'nombre'=>$request->nombre, 'tamaño'=>$request->tamaño, 'flor'=>$request->tamaño, 'hoja'=>$request->hoja, 'descripcion'=>$request->descripcion, 'foto'=>$real]);
    
    
            return back()->with('message', ['success', __("Planta creada correctamente")]);
        }
    

    The key is in the getClientOriginalName () method, which gets the name of the image. From there, whenever you leave the image in public (or in a folder within public, for which you have to take your relative route) everything will go well.

    The problem is that from now on the photo variable is mandatory, giving me an error if I want to introduce a new plant ignoring the photo, which leaves the code so if I want the photo to be an optional attribute:

    if(is_null($request->foto))
                Plantas::create($request->all());
            else
                Plantas::create(['id'=>$request->id, 'nombre'=>$request->nombre, 'tamaño'=>$request->tamaño,
                    'flor'=>$request->tamaño, 'hoja'=>$request->hoja, 'descripcion'=>$request->descripcion,
                    'foto'=>$request->foto->getClientOriginalName()]);
    
        
    answered by 18.02.2018 в 13:54