tarang19's avatar

Image upload issue Laravel 7 - File is being corrupted

in controller


public function update(Request $request, $id)
    {
        $student = Student::find($id);
        $validate = $request->validate([
            'fullname' => ['required'],
            'email' => ['required','email'],
            'address' => ['required','min:10'],
            'contact' => ['required','digits_between:10,10'],
            'dob' => ['required','date'],
            'gender' => ['required'],
            'nationality' => ['required'],
            // 'photo' => ['required','image','mimes:jpg,jpeg','max:500'],
        ]);

        if ($request->photo){
            $name = $validate['fullname'];
            $name = preg_replace("/[\s-]+/", "_", $name);
            $name = $name . '_update';

            
            $request->photo = str_replace('data:image/jpeg;base64,', '', $request->photo);
            $request->photo = str_replace(' ', '+', $request->photo);
            $imageName = $name.'.'.'jpg';
           
            \File::put(public_path('images'). '/' . $imageName, base64_decode($request->photo));
          
            $validate['photo'] = $imageName;
        }

        

        // $validate['user_id'] = $student->user_id;
        $validate['user_id'] = $student->user_id;

        $student->update($validate);

        return response () -> json(['test' => $student]);

        
    }

And My vue file


<template>
    <div class="container-fluid">
        <div class="container">
            <div class="row">
                <div class="col-12 col-xs-12 col-md-12 col-lg-12 d-flex justify-content-center">
                    <table class="table table-hover">
                        <thead>
                        <tr>
                            <th scope="col">#</th>
                            <th scope="col">Full Name</th>
                            <th scope="col">Email</th>
                            <th scope="col">Address</th>
                            <th scope="col">Contact</th>
                            <th scope="col">Date Of Birth</th>
                            <th scope="col">Gender</th>
                            <th scope="col">Photo</th>
                            <th scope="col">Action</th>
                        </tr>
                        </thead>
                        <tbody>
                            <tr v-for="student in students" :value='student.id'>
                                <td> {{ student.id }} </td>
                                <td> {{ student.fullname }} </td>
                                <td> {{ student.email }} </td>
                                <td> {{ student.address }} </td>
                                <td> {{ student.contact }} </td>
                                <td> {{ moment(student.dob, "YYYY-MM-DD").format("l") }} </td>
                                <td> {{ student.gender }} </td>
                                <td class="break_long_text"><img class="img_photo" :src="'/images/' + student.photo"></td>
                                <td class="d-block"> <button type="button" @click="editstudentprofile(student)" class="btn btn-primary mb-2" data-toggle="modal" data-target="#edit-student"><img src="/img/edit.png" /> Edit</button>
                                    <button type="button" @click.once="deleteitem(student)" class="btn btn-danger mb-2"><img src="/img/delete.png"/> Delete</button> </td>      
                            </tr>
                        </tbody>

                    </table>


                    <!-- modal -->
        <!-- Modal -->
        <div class="modal fade" id="edit-student" tabindex="-1" role="dialog" aria-hidden="true">
          <div class="modal-dialog modal-xl" role="document">
            <div class="modal-content">
              <div class="modal-header">
                <h5 class="modal-title" id="exampleModalLabel"><p v-if="current">Edit Student Profile of {{ current.fullname }}</p></h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                  <span aria-hidden="true">&times;</span>
                </button>
              </div>              
              
              <div class="modal-body">                  
                  <div class="form-group">
                    <main>
                        <form method="POST" action="/student" v-if="current"  @submit.prevent="onSubmit">
                            <div class="form-header">
                                <h1 class="form-header__title">Edit Personal Info</h1>
                                <p class="form-header__progress"></p>
                            </div>
                            <fieldset class="mailing">
<!--                                <legend class="mailing__title">Mailing Address</legend>-->
                                <label for="fullname">
                                    Full Name
                                    <input :id="current.fullname" name="fullname" autocomplete="fullname" autocorrect="off" type="text" autofocus @keydown="errors.fullname = null" onkeyup="this.value = this.value.toUpperCase();" v-model="current.fullname"/>
                                    <p class="alert-danger" role="alert" v-if="errors.fullname">{{ errors.fullname[0] }}</p>
                                </label>

                                <label for="email">
                                    Email
                                    <input  :id="current.email" name="email" autocomplete="email" value="old('email')" autocorrect="off" type="email" @keydown="errors.email = null" v-model="current.email"/>
                                    <p class="alert-danger" role="alert" v-if="errors.email">{{ errors.email[0] }}</p>
                                </label>

                                <label for="address">
                                    Address
                                    <textarea :id="current.address" name="address" value="old('address')" dir="auto" @keydown="errors.address = null" v-model="current.address"></textarea>
                                    <p class="alert-danger" role="alert" v-if="errors.address">{{ errors.address[0] }}</p>
                                </label>

                                <label for="contact">
                                    Contact <!--<span class="optional">optional</span>-->
                                    <input :id="current.contact" name="contact" value="old('contact')" autocomplete="contact" autocorrect="off" type="text" @keydown="errors.contact = null" v-model="current.contact"/>
                                    <p class="alert-danger" role="alert" v-if="errors.contact">{{ errors.contact[0] }}</p>
                                </label>
                                
                                <label for="dob">
                                    Date Of Birth </label>
                                    <input class="form-control"  :id="current.dob" name="dob" value="old('dob')"  autocorrect="off"  type="date" @keydown="errors.dob = null" v-model="current.dob"/>
                                    <p></p>
                                    <p class="alert-danger" role="alert" v-if="errors.dob">{{ errors.dob[0] }}</p>
                                <p></p>

                                <label for="gender">Gender</label>
                                <label for="gender">
                                    Male
                                    <input  id="gender" name="gender" value="Male" autocorrect="off" type="radio" @click="errors.gender = null" v-model="current.gender" />
                                    Female
                                    <input  id="gender" name="gender" value="Female" autocorrect="off" type="radio" @click="errors.gender = null" v-model="current.gender" />
                                    Others
                                    <input  id="gender" name="gender" value="Other" autocorrect="off" type="radio" @click="errors.gender = null" v-model="current.gender" />
                                    <p></p>
                                    <p class="alert-danger" role="alert" v-if="errors.gender">{{ errors.gender[0] }}</p>
                                </label>
                                <p></p>

                                <label for="nationality">
                                    Nationality </label>
                                    <select class="form-control" id="nationality" name="nationality" @change="errors.nationality = null" v-model="current.nationality">
                                        <option selected disabled>Choose...</option>
                                        <option value="1">India</option>
                                    </select>
                                <p></p>
                                <p class="alert-danger"  role="alert" v-if="errors.nationality">{{ errors.nationality[0] }}</p>
                                <p></p>

                                <label for="photo">
                                    Profile Photo 

                                </label>
                                    <picture-input 
                                      ref="pictureInput" 
                                      name="photo"
                                      id="photo"
                                      @change="onChange" 
                                      width="300" 
                                      height="300" 
                                      margin="16" 
                                      accept="image/jpeg,image/jpg"
                                      size="10" 
                                      :removable="true"
                                      >
                                    </picture-input>
                                   
                                    <p></p>
                                    <p class="alert-danger" role="alert" v-if="errors.photo">{{ errors.photo[0] }}</p>

                            </fieldset>
                                    <input class="btn btn-success mb-5 mt-2" name="submit" type="submit" value="Save and continue" />
                        </form>
                    </main>
                  </div>                
              </div>
              <div class="modal-footer">
               <!--  <button @click="addStudent" data-dismiss="modal" class="btn btn-primary">
                  Add Student
                </button> -->
              </div>
              
            </div>
          </div>
        </div>

                    <div style="display: none;" id="animatedModal" class="animated-modal text-center p-5">
                        <h2>
                            Success!
                        </h2>
                        <p>
                            Student Profile Delete Successfully<br />
                        </p>
                        <p class="mb-0">
                            <svg width="150" height="150" viewBox="0 0 510 510" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
                                <path fill="#fff" d="M150.45,206.55l-35.7,35.7L229.5,357l255-255l-35.7-35.7L229.5,285.6L150.45,206.55z M459,255c0,112.2-91.8,204-204,204 S51,367.2,51,255S142.8,51,255,51c20.4,0,38.25,2.55,56.1,7.65l40.801-40.8C321.3,7.65,288.15,0,255,0C114.75,0,0,114.75,0,255 s114.75,255,255,255s255-114.75,255-255H459z"></path>
                            </svg>
                        </p>
                    </div>

                    <div style="display: none;" id="animatedModalerror" class="animated-modal text-center p-5">
                        <h2>
                            Unsuccessful!
                        </h2>
                        <p>
                            Something went wrong please try again<br />
                        </p>
                        <p class="mb-0">
                            <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
                                 viewBox="0 0 215.038 215.038" style="enable-background:new 0 0 215.038 215.038;" xml:space="preserve">
<polygon style="fill:#F9AC54;" points="194.56,174.079 149.497,184.319 69.086,184.319 20.48,174.079 20.48,58.026 194.56,58.026
    "/>
                                <path d="M149.497,187.732H69.086c-0.237,0-0.473-0.024-0.703-0.073l-48.606-10.24c-1.58-0.333-2.71-1.727-2.71-3.34V58.026
    c0-1.886,1.527-3.413,3.413-3.413h174.08c1.886,0,3.413,1.527,3.413,3.413v116.053c0,1.594-1.103,2.976-2.657,3.33l-45.063,10.24
    C150.004,187.702,149.75,187.732,149.497,187.732z M69.443,180.906h79.671l42.033-9.55V61.439H23.893v109.87L69.443,180.906z
     M194.56,174.079h0.034H194.56z"/>
                                <path d="M77.664,133.802h-16.3v-29.24h16.3v3.021H64.763v9.421h12.121v3H64.763v10.761h12.901V133.802z"/>
                                <path d="M93.643,111.482c0.973,0,1.847,0.08,2.62,0.241l-0.461,3.081c-0.906-0.2-1.707-0.3-2.4-0.3c-1.773,0-3.29,0.72-4.55,2.161
    c-1.26,1.44-1.889,3.234-1.889,5.379v11.761h-3.319v-21.92h2.739l0.381,4.06h0.16c0.814-1.427,1.794-2.526,2.941-3.301
    C91.011,111.868,92.269,111.482,93.643,111.482z"/>
                                <path d="M110.363,111.482c0.973,0,1.847,0.08,2.62,0.241l-0.461,3.081c-0.906-0.2-1.707-0.3-2.4-0.3c-1.773,0-3.29,0.72-4.55,2.161
    s-1.889,3.234-1.889,5.379v11.761h-3.319v-21.92h2.739l0.381,4.06h0.16c0.814-1.427,1.794-2.526,2.941-3.301
    C107.732,111.868,108.989,111.482,110.363,111.482z"/>
                                <path d="M136.003,122.823c0,3.574-0.899,6.364-2.7,8.37c-1.801,2.005-4.287,3.011-7.46,3.011c-1.959,0-3.7-0.461-5.221-1.381
    c-1.521-0.92-2.693-2.239-3.519-3.959c-0.826-1.72-1.241-3.734-1.241-6.04c0-3.574,0.893-6.357,2.679-8.351
    c1.787-1.993,4.267-2.99,7.439-2.99c3.067,0,5.504,1.021,7.31,3.06C135.096,116.582,136.003,119.343,136.003,122.823z
     M119.303,122.823c0,2.801,0.56,4.934,1.679,6.4c1.12,1.466,2.767,2.2,4.941,2.2s3.823-0.73,4.949-2.19
    c1.126-1.459,1.69-3.596,1.69-6.41c0-2.787-0.563-4.903-1.69-6.35c-1.126-1.447-2.79-2.169-4.99-2.169
    c-2.173,0-3.813,0.713-4.92,2.14C119.854,117.87,119.303,119.997,119.303,122.823z"/>
                                <path d="M151.823,111.482c0.973,0,1.847,0.08,2.62,0.241l-0.461,3.081c-0.906-0.2-1.707-0.3-2.4-0.3c-1.773,0-3.29,0.72-4.55,2.161
    c-1.26,1.44-1.889,3.234-1.889,5.379v11.761h-3.319v-21.92h2.739l0.381,4.06h0.16c0.814-1.427,1.794-2.526,2.941-3.301
    C149.192,111.868,150.45,111.482,151.823,111.482z"/>
                                <circle style="fill:#EC5582;" cx="170.667" cy="54.612" r="34.133"/>
                                <path d="M170.667,92.159c-20.704,0-37.547-16.843-37.547-37.547s16.843-37.547,37.547-37.547s37.547,16.843,37.547,37.547
    S191.37,92.159,170.667,92.159z M170.667,23.892c-16.94,0-30.72,13.78-30.72,30.72s13.78,30.72,30.72,30.72s30.72-13.78,30.72-30.72
    S187.607,23.892,170.667,23.892z"/>
                                <path d="M170.667,64.852c-1.886,0-3.413-1.527-3.413-3.413V34.132c0-1.886,1.527-3.413,3.413-3.413s3.413,1.527,3.413,3.413v27.307
    C174.08,63.325,172.553,64.852,170.667,64.852z"/>
                                <path d="M170.667,78.506c-1.886,0-3.413-1.527-3.413-3.413v-3.413c0-1.886,1.527-3.413,3.413-3.413s3.413,1.527,3.413,3.413v3.413
    C174.08,76.978,172.553,78.506,170.667,78.506z"/>
                                <path style="fill:#DDDDDD;" d="M136.533,174.079l-3.413,6.827h-51.2l-3.413-6.827H3.413c0,11.31,9.17,20.48,20.48,20.48h167.253
    c11.31,0,20.48-9.17,20.48-20.48H136.533z"/>
                                <path d="M191.147,197.972H23.893C10.72,197.972,0,187.253,0,174.079c0-1.886,1.527-3.413,3.413-3.413h75.093
    c1.294,0,2.473,0.73,3.053,1.886l2.47,4.941h46.979l2.47-4.941c0.58-1.157,1.76-1.886,3.053-1.886h75.093
    c1.886,0,3.413,1.527,3.413,3.413C215.04,187.253,204.32,197.972,191.147,197.972z M7.17,177.492
    c1.587,7.781,8.48,13.653,16.724,13.653h167.253c8.243,0,15.136-5.873,16.724-13.653h-69.226l-2.47,4.941
    c-0.58,1.157-1.76,1.886-3.053,1.886h-51.2c-1.294,0-2.473-0.73-3.053-1.886l-2.471-4.941H7.17z"/>
    <g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g>
</svg>
                        </p>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    import PictureInput from 'vue-picture-input'
    export default {
        data(){
            return{
                students: [],
                current: null,
                id: '',
                photo: '',
                errors: [],
                success : false,
                selectedfile : null
            }
        },
        components: {
            PictureInput
          },

        mounted() {
            console.log('Student Profile Form');
            this.showrecords();

        },

        methods: {

            showrecords(){
                let self = this;
                    axios('/student')
                        .then(function (response) {
                            self.students = response.data;
                        })
                        .catch(function (error) {
                            console.log(error);
                        });
                    },

            editstudentprofile(student){
                //console.log(student);
                this.current = student;
                
                // this.students = student.id;
                // console.log(this.students);
            },

            onChange () {

                  console.log('New picture selected!')
                  if (this.$refs.pictureInput.file) {
                    this.id = this.current.id;
                    //this.current.photo = this.$refs.pictureInput.file.name
                    axios
                    .put('/student/' + this.id,{
                        fullname : this.current.fullname.toUpperCase(),
                        email : this.current.email,
                        address : this.current.address,
                        contact : this.current.contact,
                        dob : this.current.dob,
                        gender : this.current.gender,
                        nationality : this.current.nationality,
                        photo : this.$refs.pictureInput.file.name,
                    })
                    .then(response => console.log(response.data))
                    .catch((error) => {
                            console.log(error.response.data)
                            this.errors = error.response.data.errors;
                            this.success = false;
                            $('#animatedModalerror').fancybox().trigger('click');
                        
                        
                        
                    });
                  } else {
                    console.log('FileReader API not supported: use the <form>, Luke!')
                  }
                },

            onSubmit(){
                //console.log(this.current.photo)
                
                //console.log(this.current.id)
                //console.log(this.photo)
                 //photo : fileInput.files[0];
                 //console.log(fileInput);

                this.id = this.current.id;

                const editstudent = {
                        
                        fullname : this.current.fullname.toUpperCase(),
                        email : this.current.email,
                        address : this.current.address,
                        contact : this.current.contact,
                        dob : this.current.dob,
                        gender : this.current.gender,
                        nationality : this.current.nationality,
                        //photo: this.current.photo,
                    }

                    console.log(editstudent)
              

                 axios
                    .patch('/student/' + this.id,editstudent)
                    .then(response => console.log(response.data))
                    .catch((error) => {
                            console.log(error.response.data)
                            this.errors = error.response.data.errors;
                            this.success = false;
                            $('#animatedModalerror').fancybox().trigger('click');
                        
                        
                        
                    });

                    //console.log(this.photo);
                 
                },
            
            deleteitem(student){
                //console.log(student.id);
                axios.delete('/student/' + student.id )

                    .then(function (response){

                        $("#animatedModal").fancybox().trigger('click');
                    })
                    .catch(function (error) {
                        $('#animatedModalerror').fancybox().trigger('click');
                    });
                this.showrecords();
            }
        }

        }

</script>

<style scoped>
    .img_photo{
        height: 80px;
        width: 80px;
    }
    button{
        height: auto;
        width: 90px;
    }

    /*

       Styles for animated modal
       =========================

       */

    /* Start state */
    .animated-modal {
        max-width: 550px;
        border-radius: 4px;
        overflow: hidden;
        background: linear-gradient(45deg, #543093 32%, #d960ae 100%);

        transform: translateY(-80px);
        transition: all .5s; /* Should match `data-animation-duration` parameter */
    }

    .animated-modal * {
        color: #fff;
    }

    .animated-modal h2,
    .animated-modal p {
        transform: translateY(-40px);
        opacity: 0;

        transition-property: transform, opacity;
        transition-duration: .3s;
    }

    /* Final state */
    .fancybox-slide--current .animated-modal,
    .fancybox-slide--current .animated-modal h2,
    .fancybox-slide--current .animated-modal p {
        transform: translateY(0);
        opacity: 1;

        transition-duration: .3s;
    }

    /* Reveal content with different delays */
    .fancybox-slide--current .animated-modal h2 {
        transition-delay: .1s;
    }

    .fancybox-slide--current .animated-modal p {
        transition-delay: .4s;
    }

    .fancybox-slide--current .animated-modal p:first-of-type {
        transition-delay: .2s;
    }
</style>

in JPG file error: it appears that we dont support this file format

abc.jpg

0 likes
10 replies
Tray2's avatar

My guess is that it's not a jpg file anymore. You send a regular jpg then you decode it from base64. I suggest you use intervention to handle the uploaded file instead.

http://image.intervention.io/

jlrdw's avatar

Also why aren't you just storing the file name in the database.

Snapey's avatar

@jlrdw they are...

What happens when you have two 'John Smith' ? They both get the same photo.

You also need to apply some authorisation. Any user can upload details and photos for another student.

jlrdw's avatar

Also then have unique names:

John_Smith245.jpg
John_Smith962.jpg

Link images to correct user via a FK.

tarang19's avatar

thank you for replay when i try with unique name

following error generated

message: "file_put_contents(D:\nat_test\public\images/TARANG_ULHAS_SHAH_2020-04-11 05:11:06.jpg): failed to open stream: No such file or directory"
exception: "ErrorException"
file: "D:\nat_test\vendor\laravel\framework\src\Illuminate\Filesystem\Filesystem.php"
Tray2's avatar

Use the unix timestamp instead of a regular timestamp. Spaces in filenames almost always leads to problems.

I also suggest you use Homestead instead of wamp or xamp since you will most likely host the finished product on a kinus host. That way you don't have to worry about the direction of the slashes in your paths.

tarang19's avatar

Still image get corrupted

Controller

public function update(Request $request, $id)
    {
        $student = Student::find($id);
        $validate = $request->validate([
            'fullname' => ['required'],
            'email' => ['required','email'],
            'address' => ['required','min:10'],
            'contact' => ['required','digits_between:10,10'],
            'dob' => ['required','date'],
            'gender' => ['required'],
            'nationality' => ['required'],
            // 'photo' => ['required','image','mimes:jpg,jpeg','max:500'],
        ]);

        if ($request->photo){
            $name = $validate['fullname'];
            $name = preg_replace("/[\s-]+/", "_", $name);
            $name = $name . '_' . uniqid();

            
            $request->photo = str_replace('data:image/jpeg;base64,', '', $request->photo);
            $request->photo = str_replace(' ', '+', $request->photo);
            $imageName = $name.'.'.'jpg';
           
          // \File::put(public_path('images'). '/' . $imageName, base64_decode($request->photo));

            \Storage::disk('public')->put($imageName, base64_decode($request->photo));
          
            $validate['photo'] = $imageName;
        }

        

        // $validate['user_id'] = $student->user_id;
        $validate['user_id'] = $student->user_id;

        $student->update($validate);

        return response () -> json(['test' => $student]);

        
    }
Tray2's avatar

This is where you most likely destroy it

 $request->photo = str_replace('data:image/jpeg;base64,', '', $request->photo);
            $request->photo = str_replace(' ', '+', $request->photo);
tarang19's avatar

Thank you for replay can you please tell me best way to decode image and store it

Please or to participate in this conversation.