Darren Nolan

Computer Tech… and stuff

Darren Nolan

Thanks for the Support

Your support is welcome and much appreciated! So much that I'm happy to link back to your site for people who donate regularly or generously!

@DarrenNolan_
Such a Twit

Follow The Twit
@Darren Nolan_

PHP AWS Elastic Beanstalk, RDS, Laravel 4 (with migrations on updates)

02 Feb 2013 11:06:02pm - Dazz - 2 Comment(s)


SO! Let's recap my achievements for today. Sadly, much of what I read today on the internet was extremely unfriendly in terms of "what the hell do I _actually_ do" when it came to running custom commands after deployment, so I'll quickly recap the specifics where I found documentation not 100% hand-holding-friendly. The rest you can find on Amazon's extensive documentation site.

Today I wanted get started on my new blog code. I'm very tired of using WordPress (I still love you WordPress, honest) with one of the biggest factors I wish to address being the ability to simply deploy on Amazon Elastic Beanstalk. So today, it's get an RDS MySQL instance connected, throw Laravel on it, and then run any outstanding migrations (or just run them to start with). Dead simple.

Much of this I learnt from the developer guide on AWS documentation, which was extremely useful.  Following this guide, you'll get a new local git repo where you can throw laravel 4's app base onto (currently found here).  I won't go into it, it's already awesomely documented there on how to get to this point in the Beanstalk PHP getting started guide (Linked again in case you still haven't read that before reading on here).

Elastic Beanstalk has become even more awesome for users of Laravel, as 'composer install' is automatically run when it see's you have composer.json in your root folder of your app. So this helps a bunch in the fact we don't have to worry about either a) uploading the entire local vendor directory b) running composer on the instance ourselves after we push an update.

You'll notice after you follow the guide on using eb, you'll have yourself a directory called .elasticbeanstalk which is automatically added to the .gitignore.  In there, you'll need to make some quick adjustments to your environment's configuration file. (Not the 'config' file, but the file that is 'optionsettings.EnvironmentNameHere'.

[aws:elasticbeanstalk:container:php:phpini]
document_root=/public
composer_options=
zlib.output_compression=Off
memory_limit=256M
allow_url_fopen=On
max_execution_time=60
display_errors=On

The above is what I'm working with, you'll notice you need to ensure your document_root is the /public folder of your app, fairly straight forward, and that I turned on errors so that I can get some feedback as I develop 'in the cloud'. (10 points to me for using buzz-word-phrase).

If you wish to log into the created EC2 instances that are running your code (say, when shit goes wrong), it doesn't hurt to setup a key pair in your EC2 Management dashboard and then update the information under [aws:autoscaling:launchconfiguration] as follows in my example.

[aws:autoscaling:launchconfiguration]
InstanceType=t1.micro
EC2KeyName=mysecretkeypairname

Now we'll need to make sure that when our instances update or deploy for the first time, they run artisan migrate. We'll setup laravel's database configuration shortly so keep your pants on.

Make a new directory in your root directory called .ebextensions - This will be where all your commands run either before, as, or after your application is deployed. You can see a full list of things you can do (and when) in some more great documentation.

In our new folder, I made a new file called 01migrate.config, as it's run alphabetically and one day I may need more tasks to run from artisan after a deployment. The file simply contains the call to artisan migrate.

container_commands:
  artisanmigrate:
    command: "php artisan migrate --env=elastic"
    leader_only: true

In a nut shell, we're calling the command we're about to run 'artisanmigrate', it's running 'php artisan migrate --env=elastic', and I only want the leader of the environment (as we could have multiple instances all trying to do this at the same time) to run this command. The environment flag is important, as is (at time of writing) having 'php' in the command. I believe container_commands runs after your application is unzipped, but not before permissions are fixed up, thus it fails to run with it's shebang.

Now, you should be familiar with laravel environments, and so we find ourselves creating a new directory under app/config/ so go ahead and make mkdir app/config/elastic now.

Inside that, we'll have our database.php file which will have database settings. It needs to look like the following;

<?php
return array(
    'default' => 'mysql',

    'connections' => array(
        'mysql' => array(
            'driver'    => 'mysql',
            'host'      => $_SERVER['RDS_HOSTNAME'],
            'port'      => $_SERVER['RDS_PORT'],
            'database'  => $_SERVER['RDS_DB_NAME'],
            'username'  => $_SERVER['RDS_USERNAME'],
            'password'  => $_SERVER['RDS_PASSWORD'],
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
        ),
    ),
);

Elastic Beanstalk will give us the hostname, and other settings via the $_SERVER global, so we'll just throw these into the array that Laravel is asking for.

The fun part, where I'm sure there's a much better way of achieving this, is in your app/start.php file. As an elastic beanstalk hostname will change with ever environment you setup, I didn't want to either hardcode what was generated for the environment, use a cname domain, nor did I want to specifically say this deploy is always an elastic deployment. Hence the following code that replaces the default env detection (small addition really);

$elastic_hostname = isset($_SERVER['RDS_HOSTNAME']) ? $_SERVER['SERVER_NAME'] : 'none-existant-hostname';

$env = $app->detectEnvironment(array(

    'local'   => array('localhost'),
    'elastic' => array($elastic_hostname)

));

Basically saying where the server global RDS_HOSTNAME is set, I'll assume we're the elastic environment - so make this hostname = the elastic environment.

Ta da, once you git commit, git aws.push, and grab yourself a coffee while instances are rebuilt on Amazon's end, you should have a working copy of Laravel 4 connected to MySQL in their RDS. Huzzah! After all this, ensure your migrations folder has the sessions migration instructions in there (seek laravel documentation), setup your sessions driver to be the mysql database (again, seek someone else's documentation) and voila.

Some Notes:

When using eb on the command line to generate and update your instances, the RDS that is created with the environment WILL BE TERMINATED when you stop and/or delete the environment. So it's important to note, this setup is MOSTLY for testing on the fly. However, and in my opinion, if you were to use Elastic in production (which I so totally will when I get around to it), what I would do is NOT create a RDS when I create a new elastic application/environment, but create it manually in AWS's console/dashboard - and then in the elastic/database.php configuration - specifically put in the credentials there for the connection.

Of course thereafter I would need to setup the security access between the Elastic/EC2 and RDS myself - but then regardless of what happens to the environment - the RDS instance would always persist.

MAMP Stack (Mac Apache PHP MySQL)

23 Dec 2012 07:31:36am - Dazz - 0 Comment(s)


Install Apache PHP and MySQL on your Mountain Lion OS

Currently, there seems to be a lack of posts out there on how to get Mac Mountain Lion setup with a *AMP stack. I mean, there’s a lot of posts out there, but they’re not all helpful. The best post I’ve found is this – so I’ll be jumping into this as soon as I get apache working. Let’s try and consolidate that because at present – this mac ignorant (re: me) – has looked at too much junk to just get a dev stack running on his laptop

Mountain Lion, and a few previous versions – already have Apache and PHP installed. So absolute win on that front. Sadly when you search for MAMP or Mac Apache PHP MySQL – all you end up with is 3 odd packages you can “install” to give you what you already mostly have. Massive PITA imo.

Start by creating a new apache configuration file that it’s going to include. And use vim, because that’s what all the cool kids use, and I need to use it more.

sudo vim /etc/apache2/users/darrennolan.conf
<Directory "/Users/darrennolan/Dropbox/public_html">
    Options Indexes MultiViews
    AllowOverride All
    Order allow,deny
    Allow from all
</Directory>

<VirtualHost _default_:80>
    ServerName localhost
    DocumentRoot /Users/darrennolan/Dropbox/public_html
</VirtualHost>

Go ahead and restart apache

sudo apachectl graceful

That’s pretty much it. WINNING!

Now, it’s important to note – I put in my username “darrennolan” in this post, so replace that with your own username, and replace the directories I used to whatever you want to use. I like to have my dev machine’s public_html sync’d between all my machines – and use dropbox to do so. That is, until I start to use git properly like a boss.

Now, apache is going to be running as a user that’s not you, so whatever files you make ensure they have read permissions opened up so the apache user (_www) can read them. Typically that means files 644 and directories 755. Chmod accordingly – fix some groups up or install yourself suphp. Which I might do yet.

Next up – continue at this blog post to get PHP enabled and MySQL installed. Please note, that link is for lion and not mountain lion – so I’m sure I’ll run into some small inconsistencies like I did getting to get apache running, so standby for updates.

Update: While installing MySQL via homebrew – I didn’t want the MySQL process to run as myself, as a solution – where you need to run the following;

mysql_install_db --verbose --user=`whoami` --basedir="$(brew --prefix mysql)" --datadir=/usr/local/var/mysql --tmpdir=/tmp

Instead I ran

sudo mysql_install_db --verbose --user=mysql --basedir="$(brew --prefix mysql)" --datadir=/usr/local/var/mysql --tmpdir=/tmp

I also did not update my.cnf to give myself the huge 2G connection limit. I don’t think any production server I use will ever have such a large limit, therefore my dev machine won’t either.

Because it’s going to run as mysql – you need to chown the data files under /usr/local/var/mysql if it’s not already the right permissions.

sudo chown mysql:admin /usr/local/var/mysql/ib*

To get your PHP SQL stuff working on the Homebrew’s default socket location of /tmp (you could change it) – open up /etc/php.ini and find all instances of ‘default_socket’ and update the path to /tmp/

Lastly to make MySQL automatically start each time you boot up your mac, and as the user mysql – the file link you made in ~/Library/LaunchAgents – you’ll need to put ~/Library/LaunchDaemons – edit the file – and where username says your username, change it to MySQL.



Categories: Apache | MacOS | MySQL | PHP | Servers



Facebook Preview Thumbnail on WordPress Site (Oh how I hate you both right now)

09 Dec 2012 08:04:16am - Dazz - 2 Comment(s)



Get facebook to show a default thumbnail for your WordPress site, or a specific ‘featured’ image on post pages.

So because I’m lazy, for a really long time I’ve left facebook “attempt” to guess what image to use for my facebook shared links. Sadly facebook either gives me my twitter bird, or my white transparent logo (displayed on a white background of course…), despite having other images in my posts. So I’ve quickly hacked together this little script you can throw in your theme’s function file.

Basically, in the function – set your site’s default image location (I use my CDN because I’m awesome), guess if we’re using http or https – and if we’re on a singluar/post page – check for a featured image (you pick featured image when uploading or inserting the image into the actual post from the backend) and go from there.

Put this in your Theme’s functions.php file. You should only need to edit the default image URL – highlighted so you can see it.

add_action( 'wp_head', 'insert_image_src_rel_in_head', 5 );
function insert_image_src_rel_in_head()
{
    global $post;

    // Default thumbnail for facebook share.
    // You can either use a full link (http://darrennolan.com/some_image.png) or use CDN style.
    $image_url = "//cdn.darrennolan.com/dn-square.png";

    // If the post is singular, and has a "featured" gallery image - use it as the facebook thumbnail.
    if ( is_singular()) {
        if(has_post_thumbnail( $post->ID )) {
            $thumbnail_src = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'thumbnail' );
            $image_url = esc_attr( $thumbnail_src[0] );
        }
    }

    // As facebook is stupid, and doesn't like links without protocol, quickly guess it if we need to and throw it into the image src to use.
    if (substr($image_url, 0, 2) == '//') {
        if (isset($_SERVER['HTTPS'])) {
            $image_url = 'https:' . $image_url;
        } else {
            $image_url = 'http:' . $image_url;
        }
    }

    echo '<meta property="og:image" content="' . $image_url . '"/>' . "\n";
}

Couple of gotcha’s. Facebook caches it’s thumbnail lookups when you put your site’s link into facebook. So for testing purposes, you need to do something like http://darrennolan.com?v=1 where v=1 keeps incrementing each time you update your theme/images/functions. Sadly that doesn’t always work because facebook isn’t completely stupid.



Categories: Programming | Web | Wordpress



YouTube – Come back to the center

08 Dec 2012 05:00:38pm - Dazz - 0 Comment(s)


Get YouTube Centered in your browser again. Requires Chrome or Firefox. And a understanding how to copy/paste this script into a new script editor in Tamper(Grease)Monkey.

So if you’re like me, and hate YouTube following the new google theme of “stick to the left” like I do, install TamperMonkey (I assume you use Chrome… everyone should…) and install this script. Firefox users, you can use GreaseMonkey.

// ==UserScript==
// @name       YouTube Center Layout
// @namespace  http://darrennolan.com
// @version    1.8
// @description Center YouTube's new Layout to the middle of your screen.
// @match      http://youtube.com/*
// @match      http://www.youtube.com/*
// @match      https://youtube.com/*
// @match      https://www.youtube.com/*
// @copyright  2012+, Darren Nolan
// @require http://code.jquery.com/jquery-latest.js
// ==/UserScript==



if (window.location == window.parent.location) {
    // Disable silly CSS3 transitions that makes the page fly all over the place //
    $("#player").css("-webkit-animation", "none")
    	.css("-moz-animation", "none")
    	.css("-ms-animation", "none")
    	.css("animation", "none")
    
    	.css("-webkit-transition", "none")
    	.css("-moz-transition", "none")
    	.css("-ms-transition", "none")
    	.css("transition", "none");
    
    // Center the player, rid the padding on the left. //
    $("#player-api").css("margin", "0 auto 0 auto");
    $("#player").css("padding-left", "0");
    
    // After we get the player done, please fix up the comments a little. Nothing too fancy though, cause ant-eaters don't need fancy comments. //
 	$("[id$=-main-container]").css("-webkit-animation", "none")
    	.css("-moz-animation", "none")
    	.css("-ms-animation", "none")
    	.css("animation", "none")
    
    	.css("-webkit-transition", "none")
    	.css("-moz-transition", "none")
    	.css("-ms-transition", "none")
    	.css("transition", "none");
    
    $("[id$=-main-container]")
    	.css("margin", "0 auto 0 auto")
    	.css("padding-left", "0")
    	.css("width", $("#player-api").width());
    
}

If you’re clever – you can apply this to google+ if you like. Wonder if google will make this an optional setting one day, considering it’s just one class applied which makes it all horrible.

Update! Installation UserScript.org now available.



Categories: Chrome | FireFox



OpenCart – Adding Quantity to Category Page

15 Jun 2012 11:46:53pm - Dazz - 36 Comment(s)


Mister Karl asked me today if I knew of any methods with OpenCart to add the Quantity field (qty) to the category page, that is the products listed either in a grid or list format.  While I have previously achived this with nasty horrible server-side hacks, I thought it was probably more appropriate to find a more consistent solution that would stay present even after updating OpenCart.

Turns out, the nicest place for me to achieve this fix, was in the Theme file itself.  This fix works in version 1.5.3.1 of OpenCart and changes only one file.

The file you'll need to edit (assuming you're working with the default theme in OpenCart) is /catalog/view/theme/default/template/product/category.tpl

After you've seen the simple changes made, you should be able to adapt this to any theme you like.

<input type="button" value="<?php echo $button_cart; ?>" onclick="addToCart('<?php echo $product['product_id']; ?>');" />

Change this line to

<input type="text" value="1" class="item-<?php echo $product['product_id']; ?>" />
<input type="button" value="<?php echo $button_cart; ?>" onclick="addQtyToCart('<?php echo $product['product_id']; ?>');" class="button" />

We've added in a simple text input, given it a class of item-ProductId, and changed the Add to Cart button to call addQtyToCart instead of addToCart

Add a new line after the opening of "script"

function addQtyToCart(product_id) {
  var qty = $('.item-' + product_id).val();
  if ((parseFloat(qty) != parseInt(qty)) || isNaN(qty)) {
    qty = 1;
  }
  addToCart(product_id, qty);
}

Basically, you could do this without the "add qty to cart" function I've made, but I wanted to add in a little bit of error checking before adding something to the cart. If it's not a number, the qty will reset to 1 and continue to add the item anyway. It still uses the function addToCart, but with the additional parameter which defines the quantity to add to the cart.

Hope this helps someone out with quickly adding this to their OpenCart system, I did some googling prior to starting but sadly every solution I found demanded you pay at least $30. Which for an open-source product I thought was a little harsh of the community. Actually I thought it was pretty rude really, and down-right wrong. Don't get me wrong, I work on paid software solutions, but if you're going to use someone else's entire solution and add on a little "spit" of a feature.... Anyway. ENJOY.



Categories: OpenCart | PHP | Programming