Build A Photo sharing Website with laravel 5.2 From Scratch

In This tutorial;, we will Build A photo sharing website with laravel 5.2 from scratch . Laravel is a perfect choice for amateur projects as well as enterprise solutions. There are continuous improvement & enhancements in Laravel framework by the community developers. The recent announcement of Laravel 5.2 update contains few excellent new features. It continues the improvements made in Laravel 5.1 by adding multiple authentication driver support, simplified eloquent global scopes, implicit model binding, middleware groups, opt-in authentication scaffolding, array validation improvements, rate limiting middleware, and more. First, we will create an images table. Then we’ll cover methods to resize and share images.
some important notes on larvel 5.2 before diving The tutorial

Implicit model binding

Implicit model binding is the latest feature which automatically binds a model to a route. Below is an example in code:

What this does is behind the scenes call and inserts it into the $post variable. In Laravel 5.1, it would need to practice the Route::model method to instruct Laravel to inject the App\User instance which matches the {user} parameter in route definition. Therefore, in Laravel 5.2, the framework will automatically include this model based on the URI segment, allowing to quickly gain access to the model instances user require.

Array Validation

This is very excellent feature. For example: you have a form with an array of input fields like this:

While in Laravel 5.1 to add validation rules, it required looping through and adding the rules separately. Instead of having to do all that it’s been “Laravelized” into this:

Middleware Groups

Middleware groups enable to group many route middleware below a single, convenient key, allowing to assign several middleware to a route at once. For eg, this can be useful when building a web UI and an API within the same application. The user may group the session and CSRF routes into a web group, and possibly the rate limiter in the api group.

Rate Limiting

A latest rate limiter middleware is presently included with the framework, facilitating to easily restrict the number of requests that a given IP address can make to a route over a particular number of minutes. For eg, to limit a route to 60 requests every minute from a single IP address, user may do the following:

Collections Wildcards

When utilizing a collection and wanting to pull out data, user can now pass a * as a wildcard:

Eloquent Global Scope

In earlier versions of Laravel, global Eloquent scopes were complex and error-prone to implement; though, in Laravel 5.2, global query scopes only require to implement a single, simple method: apply.

Database Session Driver

The database session driver now covers user_id and ip_address so user can easily clear all sessions for a given user.

Hence, Laravel helps the application to stay alive and relevant utilizing established software development patterns.
note – please comment below if you were facing any problem or if you are new to laravel checkout this article

The following topics are covered in this tutorial:

  • Creating a database and migrating the images table
  • Creating a image model
  • Setting custom configuration values
  • Installing a third-party library
  • Creating a secure form for file upload
  • Validating and processing the form
  • Showing the image with a user interface
  • Listing images
  • Deleting the image from the database and server

so lets get started…..


Creating a database and migrating the images table

After successfully installing Laravel and defining database credentials from config/database.php, create a database called images. For this, you can either create a new database from your hosting provider’s panel, or if you are the server administrator, you can simply run the following SQL command:

CREATE DATABASE images

After successfully creating the database for the application, we need to create a images table and install it to the database. To do this, open up your terminal, navigate to your project folder and run the following command:

php artisan make:migration create_images_table --table=images –create

This command will generate a new MySQL database migration for us to create a table named images.

Now we need to define what sections should be in our database table. For our example, I thought id column, image titles, image file names, and timestamps should be sufficient. So for this, open the migration file just created with the preceding command and change its contents as shown in the following code:

<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateimagesTable extends Migration {

  /**
  * Run the migrations.
  * @return void
  */  public function up()
    {
    Schema::create('images', function(Blueprint $table)
    {
      $table->increments('id');
      $table->string('title',400)->default('');//the column that holds the image's name
      $table->string('image',400)->default('');//the column that holds the image's filename
      $table->timestamps();
    });
  }

  /**
  * Reverse the migrations.
  * @return void
  */  public function down()
  {
    Schema::drop('images');
  }
}

After saving the file, run the following command to execute migrations:

php artsian migrate

If no error has occurred, you are ready for the next step of the project.

Creating a image model

As you know, for anything related to database operations on Laravel, using models is the best practice. We will take advantage of the Eloquent ORM.

Save the following code as images.php in the app directory:

<?php
class image extends Eloquent {

  //the variable that sets the table name
  protected $table = 'images';

  //the variable that sets which columns can be edited
  protected $fillable = array('title','image');

  //The variable which enables or disables the Laravel'stimestamps option. Default is true. We're leaving this hereanyways
  public $timestamps = true;
}

We have set the table name with the protected $table variable. The content of which columns of the table can be updated/inserted will be decided with the protected $fillable variable. Finally, whether the model can add/update timestamps or not will be decided by the value of the public $timestamps variable. Just by setting this model (even without setting anything), we can easily use all the advantages of Eloquent ORM.

Our model is ready, now we can proceed to the next step and start to create our controller along with the upload forms. But before this, we are missing one simple thing. Where should the images be uploaded? What will be the maximum width and height of the thumbnails? To set these configuration values (think of it like constants of raw PHP), we should create a new configuration file.

 

Setting custom configuration values

With Laravel, setting configuration values is quite easy. All config values are within an array and will be defined as a key=>value pair.

Now let’s make a new configuration file. Save this file as image.php in config:

Installing a third-party library

We should make an upload form and then a controller for our image site. But before doing that, we will install a third-party library for image processing as we will be benefiting from its methods. Laravel 4 uses Composer , so it’s quite easy to install packages, update packages, and even update Laravel. For our project, we will be using a library called Intervention . The following steps must be followed to install the library:

  1. First, make sure you have the latest composer.phar file by running php composer.phar self-update in your terminal.
  2. Then open composer.json and add a new value to the require section. The value for our library is intervention/image: "dev-master".Currently, our composer.json file’s require section looks as follows:
    "require": {
      "laravel/framework": "5.1.*",
      "intervention/image": "dev-master"
    }

    You can find more packages for Composer at www.packagist.org.

  3. After setting the value, open your terminal, navigate to the project’s root folder, and type the following command:
    php composer.phar update
    

    This command will check composer.json and update all the dependencies (including Laravel itself) and if new requirements are added, it will download and install them.

  4. After successfully downloading the library, we will now activate it. For this, we refer to the website of the Intervention class. Now open your app/config/app.php, and add the following value to the providers key:
    Intervention\image\imageServiceProvider
  5. Now, we need to set an alias so that we can call the class easily. To do this, add the following value to the aliases key of the same file:
    'image' => 'Intervention\image\Facades\image',
  6. The class has a notation that is quite easy to understand. To resize an image, running the following code will suffice:
    image::make(Input::file('image')->getRealPath())->resize(300, 200)->save('foo.jpg');

Note

For more information about the Intervention class, go to the following web address:

http://intervention.olivervogel.net

Now, everything for the views and the form processing is ready; we can go on to the next step of our project.

Creating a secure form for file upload

please note – csrf protection comes out of box in laravel 5

Now we should make an upload form for our image site. We must make a view file, which will be loaded over a controller.

  1. First, open up app/http/routes.php, remove the line starting with Route::get() that comes with Laravel, and add the following lines:
    //This is for the get event of the index page
    Route::get('/',array('as'=>'index_page','uses'=>'imageController@getIndex'));
    //This is for the post event of the index.page
    Route::post('/',array('as'=>'index_page_post','before' =>'csrf', 'uses'=>'imageController@postIndex'));

    The key 'as' defines the name of the route (like a shortcut). So if you make links to the routes, even if the URL changes for the route, your links to the application won’t be broken. The beforekey defines what filters will be used before the action starts. You can define your own filters, or use the built-in ones. We set csrf, so the CSRF (Cross-site Request Forgery) checking will be done before the action starts. This way, you can prevent attackers from injecting unauthorized requests into your application. You can use multiple filters with the separator; for example,filter1|filter2.

    Note

    You can also define the CSRF protection from controllers directly.

  2. Now, let’s create our first method for the controller. Add a new file containing the following code and name it imageController.php in app/http/controllers/:
    <?php
    
    class imageController extends BaseController {
    
      
      public function getIndex()
      {
        //Let's load the form view
        return View::make('tpl.index');
      }
    
    }

    Our controller is RESTful; that’s why our method index is named getIndex(). In this method, we are simply loading a view.

  3. Now let’s create a master page for the view using the following code. Save this file asfrontend_master.blade.php in app/views/:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd">
    
    <html lang="en">
      <head>
      <meta http-equiv="content-type"content="text/html; charset=utf-8">
      <title>Laravel image Sharing</title>
      {{HTML::style('css/styles.css')}}
      </head>
    
      <body>
        {{--Your title of the image (and yeah, blade enginehas its own commenting, cool, isn't it?)--}}
        <h2>Your Awesome image Sharing Website</h2>
    
        {{--If there is an error flashdata in session(from form validation), we show the first one--}}
        @if(Session::has('errors'))
          <h3 class="error">{{$errors->first()}}</h3>
        @endif
    
        {{--If there is an error flashdata in session whichis set manually, we will show it--}}
        @if(Session::has('error'))
          <h3 class="error">{{Session::get('error')}}</h3>
        @endif
    
        {{--If we have a success message to show, we printit--}}
        @if(Session::has('success'))
          <h3 class="error">{{Session::get('success')}}</h3>
        @endif
    
        {{--We yield (get the contents of) the section named'content' from the view files--}}
        @yield('content')
    
      </body>
    </html>

    To add a CSS file (which we will create in the next steps), we use the style() method of the HTMLclass. And our masterpage yields a section named content, which will be filled with the view files sections.

  4. Now, let’s create our view file section by using the following code. Save this file asindex.blade.php in the resources/views/tpl/directory:
    @extends('frontend_master')
    
    @section('content')
      {{Form::open(array('url' => '/', 'files' => true))}}
      {{Form::text('title','',array('placeholder'=>'Please insert your title here'))}}
      {{Form::file('image')}}
      {{Form::submit('save!',array('name'=>'send'))}}
      {{Form::close()}}
    @stop

    In the first line of the preceding code, we told the Blade Engine that we will be usingfrontend_master.blade.php as the layout. This is done using the @extends() method in Laravel 4.

    Note

    Benefiting from the Form class of Laravel, we generated an upload form with the title field andupload field. , to make a new upload form, we are not usingForm::open_for_files() anymore. It’s merged with the open() method, which accepts either a string or an array if you want to pass more than one parameter. We will be passing the action URL as well as telling it that it’s an upload form, so we passed two parameters. The url key is to define where the form will be submitted. The files parameter is Boolean, and if it’s set to true, it’ll make the form an upload form, so we can work with files.

    To secure the form and to prevent unwanted form submission attempts, we will be needing a CSRF key hidden in our form. Thanks to Laravel’s Form class, it’s generated in the form automatically, right after the form opening tag. You can check it by looking at the source code of the generated form.

    The hidden autogenerated CSRF form element looks as follows:

    <input name="_token" type="hidden" value="SnRocsQQlOnqEDH45ewP2GLxPFUy5eH4RyLzeKm3">
  5. Now let’s tidy up the form a bit. This is not directly related to our project, but just for the look. Save the styles.css file in public/css/ (the path we defined on the master page):
    /*Body adjustment*/body{width:60%; margin:auto; background:#dedede}
    /*The title*/h2{font-size:40px; text-align:center; font-family:Tahoma,Arial,sans-serif}
    /*Sub title (success and error messages)*/h3{font-size:25px; border-radius:4px; font-family:Tahoma,Arial,sans-serif; text-align:center;width:100%}
    h3.error{border:3px solid #d00; background-color:#f66; color:#d00 }
    h3.success{border:3px solid #0d0; background-color:#0f0; color:#0d0}p{font-size:25px; font-weight: bold; color: black;font-family: Tahoma,Arial,sans-serif}ul{float:left;width:100%;list-style:none}li{float:left;margin-right:10px}
    /*For the input files of the form*/input{float:left; width:100%; border-radius:13px;font-size:20px; height:30px; border:10px 0 10px 0;margin-bottom:20px}

    We’ve styled the body by giving it 60 percent width, making it center-aligned, and giving it a grayish background. We also formatted h2 and h3 messages with success and error classes, andforms.

    Now that our form is ready, we are ready to progress to the next step of the project.

Validating and processing the form

In this section, we are going to validate the submitted form and make sure that the required fields are present and the submitted file is an image. Then we will upload the image to our server, process the image, create the thumbnail, and save the image information to the database as follows:

  1. First, we need to define the form validation rules. We prefer adding such values to the related model, so the rules become reusable, and this prevents the code from becoming bloated. To do this, add the following code in the image.php file in the app/models/ directory (the model that we generated earlier in this tutorial) inside the class definition before the last curly bracket(}):
    //rules of the image upload form
    public static $upload_rules = array(
      'title'=> 'required|min:3',
      'image'=> 'required|image'
    );

    We set the variable as public, so it can be used outside the model file, and we set it to static, so we can directly access the variable.

    We want both title and image to be mandatory, and title should have at least three characters. Also, we want to check MIME types of the image column and make sure that it’s an image.

    Note

    Laravel’s MIME-type checking requires the Fileinfo extension to be installed. So make sure it’s enabled in your PHP configuration.

  2. Now we need the controller’s post method to process the form. Add this method in the imageController.php file in app/http/controllers/ before the last curly bracket(}):
    public function postIndex()
    {
      
      //Let's validate the form first with the rules which areset at the model
      $validation = Validator::make(Input::all(),image::$upload_rules);
    
      //If the validation fails, we redirect the user to theindex page, with the error messages 
      if($validation->fails()) {
        return Redirect::to('/')->withInput()->withErrors($validation);
      }
      else {
    
        //If the validation passes, we upload the image to thedatabase and process it
        $image = Input::file('image');
    
        //This is the original uploaded client name of theimage
        $filename = $image->getClientOriginalName();
        //Because Symfony API does not provide filename//without extension, we will be using raw PHP here
        $filename = pathinfo($filename, PATHINFO_FILENAME);
    
        //We should salt and make an url-friendly version of//the filename
        //(In ideal application, you should check the filename//to be unique)
        $fullname = Str::slug(Str::random(8).$filename).'.'.$image->getClientOriginalExtension();
    
        //We upload the image first to the upload folder, thenget make a thumbnail from the uploaded image
        $upload = $image->move(Config::get( 'image.upload_folder'),$fullname);
    
        //Our model that we've created is named image, thislibrary has an alias named image, don't mix them two!
        //These parameters are related to the image processingclass that we've included, not really related toLaravel
        image::make(Config::get( 'image.upload_folder').'/'.$fullname)->resize(Config::get( 'image.thumb_width'),null, true)->save(Config::get( 'image.thumb_folder').'/'.$fullname);
    
        //If the file is now uploaded, we show an error messageto the user, else we add a new column to the databaseand show the success message
        if($upload) {
    
          //image is now uploaded, we first need to add columnto the database
          $insert_id = DB::table('images')->insertGetId(
            array(
              'title' => Input::get('title'),
              'image' => $fullname
            )
          );
    
          //Now we redirect to the image's permalink
          return Redirect::to(URL::to('snatch/'.$insert_id))->with('success','Your image is uploadedsuccessfully!');
        } else {
          //image cannot be uploaded
          return Redirect::to('/')->withInput()->with('error','Sorry, the image could not beuploaded, please try again later');
        }
      }
    }

    Let’s dig the code one by one.

    1. First, we made a form validation and called our validation rules from the model that we’ve generated via image::$upload_rules.
    2. Then we’ve salted (added additional random characters for security) the filename and made the filename URL-friendly. First, we get the uploaded filename with the getClientOriginalName() method, then get the extension with the getClientOriginalExtension() method. We salted the filename with an eight character-long random string, which we gained by the random() method of the STR class. Lastly, we made the filename URL-friendly with Laravel’s built-in slug() method of the STR class.
    3. After all the variables are ready, we first uploaded the file to the server with the move() method, which takes two parameters. The first parameter is the path to which the file is going to be transferred, the second parameter is the filename of the uploaded file.
    4. After uploading, we created a static thumbnail for the uploaded image. For this, we benefited from Intervention, an image processing class we’ve implemented earlier.
    5. Lastly, if everything goes okay, we add the title and image filenames to the database and get the ID with the insertGetId() method of Fluent Query Builder, which inserts the row first and returns insert_id of the column. We could also create the row with Eloquent ORM by setting the create() method to a variable and get the id_column name such as $create->id.
    6. After everything is okay and we get insert_id, we redirect the user to a new page that will show thumbnails, full-image links, and a forum thumbnail BBCode, which we will generate in the next sections.


    Showing the image with a user interface

    Now, we need to make a new view and method from the controller to show the information of the image uploaded. This can be done as follows:

    1. First, we need to define a GET route for the controller. For this, open your file routes.php in theapp folder and add the following codes:
      //This is to show the image's permalink on our website
      Route::get('snatch/{id}',
        array('as'=>'get_image_information',
        'uses'=>'imageController@getSnatch'))
        ->where('id', '[0-9]+');

      We defined an id variable on the route, and with the where() method, using regular expression, we filtered it first hand. So we don’t need to worry about filtering the ID field, whether it’s a natural number or not.

    2. Now, let’s create our controller method. Add the following code inside imageController.php in app/http/controllers/ before the last curly bracket (}):
      public function getSnatch($id) {
        //Let's try to find the image from database first
        $image = image::find($id);
        //If found, we load the view and pass the image info asparameter, else we redirect to main page with errormessage
        if($image) {
          return View::make('tpl.permalink')->with('image',$image);
        } else {
          return Redirect::to('/')->with('error','image not found');
        }
      }

      First, we looked for the image with the find() method of Eloquent ORM. If it returns the value as false, that means there is a row found. So we can simply check whether there is a result or not with a simple if clause. If there is a result, we will load our view with the found image info as a variable named $image, using the with() method. If no values are found, we return to the index page with an error message.

    3. Now let’s create the template file containing the following code. Save this file as permalink.blade.php in resources/views/tpl/:
      @extends('frontend_master')
      @section('content')
      <table cellpadding="0" cellspacing="0" border="0"width="100percent">
        <tr>
          <td width="450" valign="top">
            <p>Title: {{$image->title}}</p>
          {{HTML::image(Config::get('image.thumb_folder').'/'.$image->image)}}
          </td>
            <td valign="top">
            <p>Direct image URL</p>
            <input >
      

      You should be familiar with most methods used in this template by now. There is a new method called entities() of the HTML class, which actually is htmlentities() of raw PHP, but with some pre-checks and as Laravel’s way.

      Also, because we’ve returned the $image variable to the view (which is the database row object that we’ve gained using Eloquent), we can use it directly as $image->columnName in the view.

      We have added a permalink feature for our project, but what if we want to show all the images? For that, we need an 'all pages' section in our system.

    Listing images

    In this section, we are going to create an 'all images' section in our system, which will have a page navigation (pagination) system. There are a few steps to be followed as shown:

    1. First, we need to define its URL from our route.php file. For this, open app/http/routes.php and add the following lines:
      //This route is to show all images.
      Route::get('all',array('as'=>'all_images','uses'=>'imageController@getAll'));
    2. Now, we need a method named getAll() (there is a get method at the start because it will be a RESTful controller) to get values and load the view. To do this, open yourapp/controllers/imageController.php and add these codes before the last curly bracket (}):
      public function getAll(){
      
        //Let's first take all images with a pagination feature
        $all_images = DB::table('images')->orderBy('id','desc')->paginate(6);
      
        //Then let's load the view with found data and pass thevariable to the view
        return View::make('tpl.all_images')->with('images',$all_images);
      }

      Here, we first got all the images from the database using the paginate() method, which will allow us to get the pagination links easily. After that, we loaded the view for the user with the images data with pagination.

    3. To view this properly, we need a view file. Save the following code in a file namedall_image.blade.php in the resources/views/tpl/ directory:
      @extends('frontend_master')
      
      @section('content')
      
      @if(count($images))
        <ul>
      
          @foreach($images as $each)
            <li>
              <a href="{{URL::to('snatch/'$each->id)}}">{{HTML::image(Config::get('image.thumb_folder')'/'.$each->image)}}</a>
            </li>
          @endforeach
        </ul> 
        <p>{{$images->links()}}</p>
      @else
        {{--If no images are found on the database, we will showa no image found error message--}}
        <p>No images uploaded yet, {{HTML::link('/','care to upload one?')}}</p>
      @endif
      @stop

      We first extend the frontend_master.blade.php file with our content section. As for the content section, we first check whether any rows are returned. If so, then we loop them all in list item tags (<li>) with their permalinks. The links() method that came with the paginate class will create the pagination for us.

      Note

      You can switch the pagination template from config/view.php.

      If no rows have returned, that means there are no images (yet), so we show a warning message with a link to the new upload page (which is the index page in our case).

    What if a person uploads an image that is not allowed or not safe for work? You would not like to have them on your website, right? So there should be an image deleting feature on your website.


    Deleting the image from the database and server

    We would like to have a delete feature in our script, using which we will delete the image both from the database and from its uploaded folder. This process is quite easy with Laravel.

    1. First, we need to create a new route for the action. To do this, open app/routes.php and add the following lines:
      //This route is to delete the image with given ID
      Route::get('delete/{id}', array
      ('as'=>'delete_image','uses'=>
      'imageController@getDelete'))
      ->where('id', '[0-9]+');
    2. Now, we need to define the controller method getDelete($id) inside imageController. To do this, open app/http/controllers/imageController.php and add the following code above the last curly bracket (}):
      public function getDelete($id) {
        //Let's first find the image
        $image = image::find($id);
      
        //If there's an image, we will continue to the deletingprocess
        if($image) {
          //First, let's delete the images from FTP
      File::delete(Config::get('image.upload_folder').'/'.$image->image);
      File::delete(Config::get('image.thumb_folder').'/'.$image->image);
      //Now let's delete the value from database $image->delete(); //Let's return to the main page with a success message return Redirect::to('/')->with('success','image deleted successfully'); } else { //image not found, so we will redirect to the indexpage with an error message flash data. return Redirect::to('/')->with('error','No image with given ID found'); } }

      Let’s understand the code:

      1. First, we look at our database, and if we have an image with a given ID already with the find()method of Eloquent ORM, we will store it with a variable called $image.
      2. If the value of the $image is not false, there is an image matching the image in our database. Then, we delete the file with the delete() method of the File class. Alternatively, you can also use the unlink() method of raw PHP.
      3. After the files are deleted from the file server, we delete the image’s information row from the database. To do this, we are using the delete() method of Eloquent ORM.
      4. If everything goes smoothly, we should redirect back to the main page with a success message saying the image is deleted successfully.

      Note

      In practical application, you should have a backend interface for such actions.

       

      Wrapping up

      In this tutorial , we’ve created a simple image sharing website with Laravel’s built-in functions. We’ve learned how to validate our forms, how to work with files and check their MIME types, and set custom configuration values. We’ve learned more about database methods both with Fluent and Eloquent ORM. Also, for image processing, we’ve installed a third-party library from packagist.org using Composer and learned how to update them. We’ve also listed images with the page navigation feature and learned to delete files from the server.

      hope you will like it :)

Deven Rathore

Deven is an Entrepreneur, and Full-stack developer, Constantly learning and experiencing new things. He currently runs CodeSource.io and Dunebook.com.

Published by
Deven Rathore

Recent Posts

3 Ways to Get the Most Out of Your University’s Virtual Computer Lab

IT is more important than ever in the world of higher education, and yet with…

21 hours ago

Top Tips for Learning Java Programming

If you’re here for the top tips, we assume you’re ahead of the “how to…

1 day ago

Neural Networks for Creating Blog Texts

The world is progressing at unprecedented rates at the current moment, especially in terms of…

2 days ago

Top 20 Opensource Python Tkinter Projects

This article will highlight the Top 20 Opensource Python Tkinter Projects which we believe will…

4 days ago

Beginners guide to Sneaker Proxies

With their numerous applications in streamlining the data flow, securing both the servers and the…

1 week ago

Top 20 Node.js dashboard templates

In this article, We will be looking at some of the top Node.js dashboard templates.…

1 week ago