Tutorials (51)


Backups to Amazon S3 the Easy Way

I was looking for a simple solution to backup my newly constructed server to an off-site location in case something were to happen. I don’t mean I lost a file… more like catastrophic hardware failure, fire, water damage, physical damage, and even theft!. Local backups really are best, and I don’t plan on abandoning them any time soon, but in the case of the one in a million chance where something like this occurs, there’s a high likelihood that everything might be lost.

Enter Cenolan.com: How to: Incremental Daily Backups Using Aamazon S3 Duplicity. It really is pretty easy. Just one thing: besides installing Duplicity (also required a few other dependencies), I had to install Python-boto: yum install python-boto

You may also be interested in doing regular backups of your MySQL database (from HowToForge.com)




Adding the Fedora Install DVD to Your Yum Repo List

I recently performed a major upgrade on my file server this week. It was a lot harder than it should have been, but that’s only because my Linux Foo can only go this far. Two to three re-installs later on the new hardware it was getting old, so I told the Fedora installer to just do the base package and I would worry about the rest later.

Worry is not my middle name, but frustration might be. For reasons unknown to me I thought I could just do an “upgrade” from the installer. Wrong. Then I thought maybe I could boot normally, insert the DVD, and I could then select it as a package source. Wrong. Download all those packages I missed the first time around isn’t an option on slower-than-molasses connection I have at home. So I did what any other self-respecting nerd would do – turn to Google.

The trick lies in the Yum Repos list, located in /etc/yum.repos.d/fedora.repo

Check it out. Normally you have three entries: Fedora, a Debug branch, and a Sources branch. The primary Fedora branch configs look something like this (I’m using Fedora 10 in my example) :


[fedora]
name=Fedora $releasever - $basearch
failovermethod=priority
baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever
/Everything/$basearch/os/
mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-$releasever&
arch=$basearch
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch

Our job is to copy and modify it so Yum and the GUI app manager can use the DVD. First you need to copy the block of code pertaining to [fedora] and paste the copy into your file – after [fedora] is fine.

  1. Change the line [fedora] to [fedora-dvd]
  2. change the name line to name=Fedora 10 x86_64 - DVD
  3. change the baseurl line to baseurl=file:///media/Fedora%2010%20x86_64%20DVD (the path to your DVD might be different – check it first)
  4. delete the mirrorlist line
  5. make sure the enabled line is enabled=1 (you can turn it off later through the “Software Sources” app)
  6. Save and exit

Use Yum or the Application manager to install. Rather than taxking your network and your patience you’ll see the DVD activity light busily blinking as you begin installing packages. One tip you might need to keep in mind is that refresh packages button on the package manager. There were a few packages I tried installing that were no longer available when I turned-off the net-based repo source. This is equivalent to yum clean [option]

Happy installing!




Nasty WordPress Worms

I just ran across a nasty worm in one of my WordPress blogs (not the most current install). Not only did it overwrite a ton of files, inserting spam links and malware into the pages, but it was sneaky enough to go into my wp-admin/.svn/prop-base/ directory and re-write those files as well. It’s fairly ingenious from the hacker standpoint. Most people like me will rely on the svn revert file.php to send the file back to its original version. That won’t work if the .svn/prop-base files are altered because svn will see that they are the same – it doesn’t bother actually checking the repo, so you’re stuck with infected files.

I solved my problem by deleting the wp-admin directory and doing an svn-up on its parent. That forces SVN to say “hey – that directory is missing. I should pull it down from the repository.” Problem solved (for now).

And I am now running the most current version of WordPress, so hopefully I’m free of risk and infection from here on out.




Fixing a Broken TimeMachine Backup

I had the unfortunate event of having to send my MacBook Pro into Apple for some repairs. The machine came back working fine, however there was something odd going on with TimeMachine – it wanted to do a full backup of my disk. Odd, considering I keep it plugged-in all the time when I’m at my office desk. I tried re-selecting the disk, but that didn’t work. Clearly this would require some detective sleuthing on my part.

There are a couple points you need to know.

* First of all, check the Apple Support forums. They have some good information on there, but most of it is pretty basic. Start there then move on if you haven’t quickly solved your problem.

* Time Machine disks know your computer by the MAC address. This was the root of my problem – it seems my mac address had changed (new logic board?).

* I eventually found my solution at MacOSXHints.com, however I had to do a little more work to actually get everything working. See below.

What made this a step more difficult was that the MacOSXHints solution didn’t quite work, however one reader commented on a unique situation that resembled mine. in the /Volumes/TimeMachine/Backups.backupdb directory there were MyComputerName and “MyComputerName 2” directories. The former had all my backups in there, the latter didn’t have any completed backups and showed a file creation time of today, not the last time I ran a backup. So with the ACL turned off (see the directions) I removed the “MyMachineName 2” directory (mind you – I had already completed all the steps on MacOSXHints.com before trying this. It might be important). It worked.

YMMV but hopefully this will work for you.




CakePHP: Storing Configs in your DB

There are many situations in web apps where site-wide configurations need to be accessible to users through admin interfaces, rather than configuration files residing on the server. It is a practical method of storing configuration values that may need changing from time to time, but without access to the core configuration file.

UPDATE (2008-10-22): This article has been published to the CakePHP Bakery

Code

Settings are stored in the database, so we will first need to start by creating the table:
CREATE TABLE settings (
id int(10) unsigned NOT NULL auto_increment,
key varchar(48) NOT NULL,
value text,
PRIMARY KEY  (id),
UNIQUE KEY key (key)
)

Next, go ahead and bake your model and controller, but don’t worry about baking-in some of the pre-built methods. Modify your model to look like this:

class Setting extends AppModel {

var $name = ‘Setting’;
var $key = ‘MyApp’;

//retrieve configuration data from the DB
function getcfg(){
$key=$this->key;
$cfgs = $this->find(‘first’,array(‘fields’=>array(‘id’,’key’,’value’)));

if (count($cfgs)) {
$this->checksum=$cfgs[‘Setting’][‘value’];
$cfgVal = unserialize($cfgs[‘Setting’][‘value’]);

}
Configure::write($key,$cfgVal);
}

//write configuration data back to the DB
function writecfg(){
$key = $this->key;

$rev = Configure::read($key);

$value=serialize($rev);

//if the configs haven’t changed, no need to save them
if ($value==$this->checksum) return;

//otherwise the configs have changed, so

$this->data = array(‘key’=>$key,’value’=>$value);

if ($setting = $this->findByKey($key)) {
$this->data[‘id’] = $setting[‘Setting’][‘id’];
}

$this->save($this->data);
}
}

You’ll notice that Configure:: values are serialized and stored together using the MyApp Configure::key. At first this may seem somewhat counter intuitive to how we think we should store configurations. However, consider the hassle involved with trying to figure out how/where to store multi-dimensional arrays in an inherently flat storage system (db). It’s probably doable, but not without considerable headaches. Storing everything in a serialized string allows Cake to worry about creating the structure – we just save the output.

Next, open up your app_controller.php file and add the following code to the top of the class:
var $uses = array('Setting');

You will also need to add some code to your AppController beforeFilter() and afterFilter() methods:

class AppController extends Controller {

var $uses = array(‘Setting’);

function beforeFilter(){
//reads the site-wide config values from the DB and puts them through the Configure::write method
$this->Setting->getcfg();
}

function afterFilter(){
//retrieves the site-wide configurations from Configure::read($key) and puts it back into the db if new
$this->Setting->writecfg();
}
}

Usage

Any place you would like to store a Configure:: value in the database, you only need to use the $key specified in the model. If you don’t, the values will not get saved. An example would look something like:
<? Configure::write('MyApp.themeName','My Great Theme'); ?>

Since the retrieval code is run in the before filter, we can treat the Configure:: vars like any others in our app when we need to access them. To recall a value we would run something like:
<? $myVar = Configure::read('MyApp.themeName'); //returns 'My Great Theme' ?>

Next Steps

Because this is only a very simple way to store configuration data (one row for the entire app), there will likely be some desire to extend it. You may wish to segregate certain data into their own rows (perhaps individual plugins or components), which would only require some additional code to accept additional keys for read/write access. That, my friends, is a job for another tutorial.




HABTM Unit Testing in CakePHP

I use this blog quite a bit for documenting little quirks, bugs, work-arounds, neat things, and tutorials so that I know where I can find the solution in the future. At the same time, you benefit by hopefully not having to go through some of the same messes I did just to get to this point.

I love CakePHP so far (but still quite the noob), but my biggest gripe is the documentation. The basics are there, but there’s often too little documentation to get the novice going. From the Bakery docs, it’s not exactly clear how to perform tests on models when HABTM (has and belongs to many) relationships are involved. Have no fear, it’s doable (though not straightforward).

Hopefully you baked your MVC pieces and included test scripts to go along with them. If not, do that first. The key part to getting the tests for models that have HABTM relationships is to set-up a fixture representing the table that stores the relationship. Don’t actually set-up the test – just the fixture.




Zend Framework – Getting Started

Working with a new client project this week that requires the Zend Framework. It’s not my choice of frameworks, but I’m still eager to get going on it. As I’m a bit more familiar with CakePHP, I thought it would be wise to watch a screencast or two about getting started on ZF to see what some of the main differences are. Watch them (from Mitchell Hashimoto).




Unchecked checkbox values

Working with form check boxes can be a bit of a pain on sites with dynamic content. Saving the checked data is easy, but how do you easily save the unchecked value without manually adding it to an array from inside your code? Keep reading.

revealCMS is working great – I’m really starting to see a lot of its strengths (and, admittedly, some weaknesses) as I use it more and begin extending it. Due to how data is saved to the database, the HTML checkboxes were a bit of a problem when trying to save their unchecked state. Typically I save the post data to the object, where it is filtered and scrubbed, as necessary.Only the posted values get updated in their respective rows (makes sense, right?).

The problem is that unless a box is checked, it’s not going to be sent with the form – a problem if you have a checked box, but want to save the unchecked state.The first option is easy and probably the first solution you’d think of – write a couple lines of code for every single checkbox and set it to some default value if it’s left unchecked when the form is posted. Fine, but that takes more thinking than I want to do for something so simple, and it’s somewhat prone to error. Instead…

…the solution: Insert a hidden form field with the same name as the checkbox and the default value right before the place where the checkbox is located:
<input type="hidden" name="box1" value="0" /> <input type="checkbox" name="box1" value="1" />
What happens here is that when the checkbox is left unchecked, the hidden field’s value gets submitted, as-is. When the check box is checked, the hidden field’s POST value gets overwritten by the activated checkbox’s.
Unactivated: Hidden field’s value.
Activated: Check box’s value.

Told you it was easy!




SMARTY: Assigning variables to the header from the body

The problem recently presented itself to me when writing some new functionality for revealCMS: I needed to set some variables to load in the page head, but could only be set after a portion of the body had completed rendering. I wrote a plugin that essentially loads a different stylesheet depending on the input of the Smarty template function. The hard part wasn’t assigning the variable – it was figuring out the best way to get that assigned data to appear in a part of a page that had already been rendered – the head.

It makes sense why Smarty would work this way – that you can’t go back and re-assign variables. It would be too messy. So somehow you need to assign the variable first in the body, then go back and render the head. It’s simple… really. Believe it.

But why bother? Why not put <style> tags directly into the page body where the plugin is located? The reason is simple: <style> tags (and <script> tags, for that matter) MUST be in the page header. It’s a web standards thing.

First, break-up your page templates into two sections: the header (containing everything before the <body> section of your template), and the body, which contains the <body> section. First render the body using
$body = $smarty->fetch('body.tpl');
At this point, I’ll just assume that your page functions have loaded and you’ve either placed an {assign} tag somewhere in the template, or you’ve used a $smarty->assign() inside the template function. If you’re not familiar with $smarty->fetch(), it’s just like $smarty->display(), except it outputs the contents to a variable rather than the screen. And just like display() it can also take $compile_id and $cache_id as optional parameters.

Now render the head:

$head = $smarty->fetch('header.tpl');
By this point everything should work-out as we expect it. Our dynamically loaded css file is loaded in the head and our standards friends are happy. The beauty about this example is that you can now render a number of items in any order you need them then display properly, so long as it makes logical sense.

Here’s a tip: You can use this method to dynamically load javascript files and frameworks if your fancy web 2.0 page functions/plugins need it at some times, but not at others.




Replacing Substrings using SQL, not PHP

Let’s say you have a problem: A recent DB migration has escaped a lot of quote marks within your fields and now your app is acting funny. Your task is to fix the problem, and do it FAST.

Enter the replace() function in MySQL (assumed other RDBMs as well, such as Postgres and MSSQL)
UPDATE table_name SET table_field = replace(table_field, ‘replace_that’, ‘with_this’);

I was seeing a lot of ” text in some forums output, so I was on a mission to make nice with the forums administrator:
update posts_text set post_text = replace(post_text,'\"', ‘'"'’);
Double backslash? Yes. Quotes are OK, but the backslash is an escape character, so to actually print the backslash, you need to escape the escape character. You’d do the same if you wanted n to not be treated as a newline return: \n