Martin Carlin

I recently had to deal with migrating legacy systems to a Laravel 5.4 app, as you might have guessed, the legacy app was using sha1 and not bcrypt.

Here is how I managed to silently update sha1 passwords to the more secure bcrypt version:


namespace App\Listeners;

use Illuminate\Auth\Events\Attempting;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

use App\User;

use Hash;

class CheckOldHashedPassword
     * Create the event listener.
     * @return void
    public function __construct()

     * Handle the event.
     * @param  Login  $event
     * @return void
    public function handle(Attempting $event)
        $user = User::where('email', $event->credentials['username'])->first();

        if (!empty($user) && $user->password === sha1($event->credentials['password'])) {
            // update password
            $user->password = Hash::make($event->credentials['password']);

Just created the above file in app\Listeners.

Depending on the name of your login field, you might need to change the array key being used in $event->credentials, possibly username or email.

If you are using md5 or something else, then you can easily add in the checks that you need.

Just a quick post about how to use Laravel Echo without the npm package.

The way I did it was to add it to my local project as per the docs:

npm install --save laravel-echo pusher-js

Then I copied the node_modules/laravel-echo/dist/echo.js file to my public/vendor directory.

Then I just updated my scripts partial to include the Echo js file and the Pusher library:

<!-- Echo -->
  var module = { };

<script src="{{ cached_asset('vendor/echo.js', true) }}"></script>

<!-- Pusher -->
<script src="{{ cached_asset('vendor/pusher.min.js', true) }}"></script>

  window.Echo = new Echo({
    broadcaster: 'pusher',
    key: '{{ config('broadcasting.connections.pusher.key') }}',
    cluster: 'eu',
    encrypted: true

The var module = { }; is needed because how it's meant to be used with webpack I think, I picked that up from a Stack Overflow answer.

I've been trying to figure this out for a while before I cracked it:

Users Controller

use Illuminate\Foundation\Auth\SendsPasswordResetEmails;

class Users extends Controller

    use SendsPasswordResetEmails;

    public function resetPassword(Request $request, $id)

        // your response

The form I used in my view is

<form id="password-reset-form" action="/users/{{ $user->id }}/reset-password" method="put">
   {{ csrf_field() }}
   <input type="hidden" name="_method" value="put">
   <input type="hidden" name="email" value="{{ $user->email }}">
   <button type="submit">Reset Password</button>

Then all you need is a route

Route::put('users/{id}/reset-password', '[email protected]');

Apologies if this is obvious, but thought it could possibly help others. I had this link on a product detail page to redirect back to the results page:

<a href="{{ URL::previous() }}">Search Results</a>

but after the page reload triggered by adding the item to the basket, that link would go 'back' to the same page (not to mention the possibility of navigating to the page from somewhere other than the results page). I couldn't think of any way around it but managed to fix it by updating the controller method for the search results page. The items are fetched using the inbuilt paginator:

/* query logic */

$items = $items->paginate(15);

$url = $items->url($items->currentPage()); // e.g. /some-url?page=1

// then append all the get params to the string from above
foreach ($request->all() as $key => $value) {
    $url .= '&' . $key . '=' . $value;

$request->session()->put('results-route', $url);

then use <a href="{{ Session::get('results-route') }}">Search Results</a> instead.

Not sure if there's a neater way but chuffed I managed to come up with a solution, had no idea how I was going to fix that.


After writing the first version of the post, I wanted to go back to have another look at it as I wasn't quite happy.

I was running php vendor/bin/dep for deploys since I installed Deployer as a local package.

I changed that by installing globally composer global require deployer/deployer.

Then I could use dep instead of php vendor/bin/dep.

I then removed all of the tasks that were already defined in the Deployer Laravel recipe from my script to avoid cluttering. I didn't even notice that include before so I'm glad I went back to have another look at this.

After that I setup some variables at the top to avoid any confusion over what needed updating for individual use cases.

I also followed the Laravel recipe and included the .env in the shared_files array.

The biggest change after that was to simply upload the public/build directory and its contents over having to do npm install and then gulp --production.

This makes the deploy significantly quicker and it also saves you having to install node and npm on production, as well as not having a node_modules directory for every release which would take up a significant amount of room.

I was still having issues with the bootstrap/cache folder after my re-shuffle, so I removed that line from the top level .gitignore (can't remember if it was me that added that or not, but looking at Laravel's .gitignore it must have been me) and that helped and saved needing a further task in the deploy. There is already a .gitignore in the bootstrap/cache directory so that nothing in there will be version controlled, but just having the empty directory saved endless amounts of pain.

The final piece of the puzzle was to run chmod g+s <directory> to make files inherit group to make files inherit the group from the parent directory (my parent directory had martin:nginx as the owner and group). Without that, all the newly deployed files were martin:martin which didn't work for my configuration since nginx is running as .... nginx.

New gist:

I recently tried using Deployer for the first time to setup a deployment process for a Laravel 5 project, rather than using something like Capistrano that would require installing ruby and gems rather than just adding a Composer package.

This gist represents hours of heartbreaking errors trying to figure out why things weren't working, the main one being the first task:

 * Create cache folder in bootstrap directory
task('deploy:cache_folder', function() {
  run('mkdir {{release_path}}/bootstrap/cache');
})->desc('Manually create cache folder');

I was getting an error saying that bootstrap/cache/services.php didn't exist when trying to run php artisan optimize. The solution seems to be creating the bootstrap/cache directory but of all the tutorials and blog posts I read, none mentioned it so I'm not sure if this is a recent change since the .gitignore file has /bootstrap/cache in it but a 5.1 project I have doesn't.

I think the rest is fairly self-explanatory, just replace the placeholders in the square brackets, the curly brackets are actually used by Deployer so don't change those!

This example is made a bit more complicated due to using elixir for assets, so that's why we have to have a task that runs npm install.

I also wasn't sure what to do with the .env file since it's not in source control and obviously your local one will be based on a local environment, not production, so I decided just to create a .env.production file that gets uploaded and renamed to .env. The only problem I can see there is that if you are part of a team then you'd need to communicate any changes somehow since it's not meant to be version controlled.

To deploy, run dep deploy.

If you have any suggested improvements then I'd love to hear them.