John Main Logo

John Main

Code. Design. Hosting. Maintenance.

14
Aug '17

Maybe a bit of a niche thing to to here, but I found myself needing to do this as part of the process of transparently transitioning a site from an older framework. In effect I had two different apps with mod_rewrite rules to determine which served which pages. Critical to this was that I needed to make sure that these pages shared authentication and session data.

To start I had to move the authentication logic into the new Laravel app, as this would become the gatekeeper and the primary source of the session data. Then for all pages being served by the old app, I came up with the following to be included in the front controller of the old app, before its own app was initialised (we’re assuming here that “LARAVEL_ROOT” has been defined as the path to the Laravel application root):

require_once LARAVEL_ROOT . '/bootstrap/autoload.php';
$app = require_once LARAVEL_ROOT . '/bootstrap/app.php';
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
if(!empty($_COOKIE[$app['config']['session.cookie']])) {
$id = $app['encrypter']->decrypt($_COOKIE[$app['config']['session.cookie']]);
$app['session']->driver()->setId($id);
$app['session']->driver()->start();
if($app['auth']->check()) {
/*
Now I have access to the Laravel session via $app['session']->driver()
e.g. $app['session']->driver()->get('site');
And access to the auth logic via $app['auth']
I can also call any registered facades too
e.g. \Auth::user() \Request::get() etc
*/
}
}

It’s best to to go too far off-piste here in terms of what you’re pulling out of your Laravel app, but it should give you all you need to share authentication and other critical session data.

04
Jul '17

This was a bit of a challenge to myself to make PDF rendering much more simple to implement.

I came up with this middleware which will trigger if the request contains a ‘pdf’ parameter. As an additional nice-to-have if the request has a ‘ls’ parameter it will render landscape rather than portrait.

This uses Snappy PDF and assumes it is aliased simply as ‘PDF’ in the app config.

namespace App\Http\Middleware;
use Closure;
class PDF
{
/**
* Handle an incoming request.
*
* @param  \Illuminate\Http\Request  $request
* @param  \Closure  $next
* @param  string|null  $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if($request->pdf) {
//Useful to have in case there are any view changes that help with the render
view()->share('pdf', true);
view()->share('print', true);
//Grab the response into a variable
$response = $next($request);
//Try to get title from the response, if not just take app name
$title = (is_object($response->original) && $response->original->title) ? $response->original->title : config('app.name') . '.pdf';
$orientation = $request->ls ? 'landscape' : 'portrait';
return \PDF::loadHTML($response->content())->setOrientation($orientation)->stream($title);
}
return $next($request);
}
}
29
May '17

Like me, you may find the jQuery $.getJSON function really useful for quick GET-based AJAX calls, and lament the lack of a corresponding POST function. Well here it is:

$.postJSON = function(url, data, func) { $.post(url, data, func, 'json'); }

You’re welcome!

02
Mar '17

As you probably know, for CLI PHP the pcntl_fork command works great for forking off new processes and allowing you to do some fun asynchronous things. However that command is generally not available when running as a web process via an apache handler or similar. I found myself wanting to have some asynchronous actions to be triggered via the web frontend and, after a bit of thought, I came up with the following:

exec('php ' . __FILE__ . ' &> ' . __DIR__ . '/output.txt &');

What we’re doing here is using an exec function to execute our current file in a process, push all output to a file (you can push to /dev/null if you want instead) and run it in the background. Hence the exec command will return immediately, the process will be off and doing its own thing, and you have, in effect, forked your process.

Now I know that if you’re using a full framework then there are better things you can do with queues, events, crons etc, but for a light script this can be pretty helpful.

As an additional quick help, if you want logic to be conditional on the process being executed then you can use the following to tell if you’re in CLI mode or not:

stripos(php_sapi_name(), 'cli') !== false
10
Jan '17

Ever found yourself constantly pulling things out of the session to use in controller actions and thinking there must be a better way? Ever tried implementing a constructor to set instance variables but finding them empty? Well I’ve got your back.

The reason that simply populating instance variables in a controller constructor is that the constructor will be run before any middleware is triggered, and hence the session won’t be available to read from, the \Auth::user() won’t be populated etc etc. The way round this is to define a middleware closure in your constructor, which will run after all the other middleware, and ensure that the session etc is available to use here.

This is just a little example to make the current user and site directly available to controller actions. I also tend to put these in shared abstract base controllers for all the other controllers to inherit from, but that’s just me.

protected $active_user;
protected $active_site;
/*
* Constructor
*/
public function __construct() {
$this->middleware(function ($request, $next) {
$this->active_user = \Auth::user();
$this->active_site = session('site');
return $next($request);
});
}
13
Nov '16

Easy one this, just copy and paste code if you’re using Bootstrap.
Whenever a tab is changed, this code will take its ID from the trigger and put into the window location hash (AKA address anchor or, if you’re really posh, the fragment identifier).

//Remember tab state
$('ul.nav-tabs > li > a').on('shown.bs.tab', function(e) {
if($(e.target).attr('href')) {
var id = $(e.target).attr('href').substr(1);
window.location.hash = id;
}
});

The second section of code ensures that whenever the page is reloaded, or the page is linked to using a valid tab ID, the identified tab will be selected automatically.

//Switch tab state
if (window.location.hash) {
$("a[href='" + window.location.hash + "']").tab('show');
}

Done

01
Sep '16

Quick one here, but one that it took me a while to discover so I thought I’d share it. If you want to have your script change the current address without actually navigating anywhere, you can push to the browser history using the following command:

History.pushState({}, title, url);

The latest item in the history will always display as the current URL in the address bar.

I find this particularly useful when I have a lot of dynamic elements on a page, particularly tabs and accordions.
For example if I wish to retain an opened tab across a page refresh I can use this trick to change the window location hash then use a simple script like this to switch to that tab on page load:

if (window.location.hash) {
$("a[href='" + window.location.hash + "']").tab('show');
}
11
Apr '16

If you’re trying to install or update packages via yum on a RedHat /CentOS server and you keep getting ‘Multilib’ errors along the lines of:

Protected multilib versions: openssl-1.0.1e-42.el6_7.4.x86_64 != openssl-1.0.1e-42.el6.i686

Then this means that you already have a 32bit version of a package and you’re trying to install a 64bit version (either by direct installation or as a dependency), or vice-versa. Generally these days you will be operating on a 64bit system so this issue can be very easily fixed by running the following

yum remove *.i386 *.i486 *.i586 *.i686

And then installing the 64 bit versions (these should be the defaults) of the offending packages.

I encountered this when trying to use a 64 bit CentOS image as an AWS server due to 32 bit packages being pre-installed. Good grief it took me a while to figure out!

03
Jan '16

When building controllers I, along with many others I’m sure, generally create an abstract ‘base’ controller to contain some standard functionality, and which all the other controllers can extend. I use these for common pre/post processing functions, session management and all sorts of other stuff. This works well for a simple site, however there are many instances where controllers can’t all extend the same base class – for example if you want to setup shared CRUD functionality this will have to be different with normal vs nested resources. Where I have controllers that can’t all extend the same base class but still need to have some functionality in common I like to use a trait. A key example of this is when handling JSON responses I tend to use the following trait:

trait JSON {
/**
* Send success
* @param string [$message='OK'] Message
* @param integer [$response_code=200] Response code
*/
protected function sendSuccess($message = 'OK', $response_code = 200) {
return $this->sendResponse([], $message, $response_code);
}
/**
* Send failure
* @param string [$message='Error'] Message
* @param integer [$response_code=404] Response code
*/
protected function sendFailure($message = 'Error', $response_code = 404) {
return $this->sendResponse([], $message, $response_code);
}
/**
* Send error
* @param array $data Data
* @param string [$message='OK'] Message
* @param integer [$response_code=200] Response code
*/
protected function sendResponse($data, $message = 'OK', $response_code = 200) {
$data = ['success' => ($response_code >= 200 && $response_code < 300), 'message' => $message, 'data' => $data];
return response()->json($data, $response_code);
}
}

This code is written for Laravel 5, but could easily be adapted to another framework.

10
Nov '15

I love most of the new features of Laravel 5, but it definitely has its drawbacks – a specific one as far as I’m concerned is the new way of managing configuration files. In Laravel 4 we all got very accustomed to being able to have a full set of configuration files for each environment, with any level of nesting and complexity we liked, but now everything we want to do on a per-environment basis has to be defined within flat .env files. Having said that I do completely accept that it is better in terms of safety to have a single, non-version-controlled environment config file, rather than a whole bunch which, lets be honest, we all ended up putting under version control, passwords and all!

So in an effort to embrace the new structure whilst maintaining some of the function of the old, I came up with a little script to allow some futher complexity to my .env files. When this is added to the ‘boot’ method of the ‘AppServiceProvider’ class it allows multiple pipe-separated values do be pre-processed into an array within the config structure:

if(env('MY_ENV_VALUE')) {
config()->set('app.my_env_value', explode('|', env('MY_ENV_VALUE')));
}

Really really simple stuff but good grief does it make a difference!