php.ie slowly upgrading

It’s been a while since I wrote anything vaguely technical. I guess it’s because I like to write only when there’s something new to say, and usually only if I have some new code to give away.

No new code today, but I can describe the recent work on php.ie (I’m the secretary of the Irish PHP Users’ Group).

So firstly, it was basically a static/brochure site for about a year, until we installed WebME (written by me!) as the CMS and created a skin for it so there’s only a tiny design difference. If you want to try out WebME, then download the SVN version from the google code site, or create a test site here (uses a really old version of WebME – you’re better off using the SVN version).

Then, I started rewriting the right panel. Beforehand, it displayed recent twitter messages, but they’re not often put out so it was a bit of a wasted space.

The panel now uses a WebME widget which displays recent Twitter messages, emails from the mailing list, and posts from the forum.

Over the next few days, I’ll be adding a new News section to the site, and the message widget will be able to show new articles from planet php.ie and new jobs from the jobs page.

I’m currently reading through Ken’s linux.ie todo list to see what I can appropriate for php.ie for its ongoing development.

Big thanks go to Michele and the team at blacknight for hosting the site.

Oh! Just a reminder, buy my book! JQuery 1.3 with PHP – hasn’t been reviewed by anyone yet, as far as I know, but my own opinion is that it is worth having on your shelf if you are a PHP developer that wants to step into jQuery.

jQuery 1.3 With PHP: cover mockup

6989_MockupCover

I’ve been sent a mockup for the book’s cover. The suggested title of the book is “jQuery 1.3 with PHP”. The working title was “PHP and jQuery”. Which do you prefer?

The book has been completed, in that all the chapters are written, and it’s in the final edit phase at the moment. This involves Packt having a technical editor try everything in the book just to iron out any kinks. It’s already been gone over by three other reviewers, and the only problem appears to have been with the File Management chapter, where the web-server was IIS on Windows. That should be solved by the time the book comes out.

I’ve learned a lot while writing this book. A major point that keeps raising its head is that I keep using colloquialisms and aphorisms (ha! “raising its head”), and those are not globally understood. Another is that I keep using British spelling, but it’s expected that most readers will be American.

From a coding point of view, I tend to write compact code with comments only appearing where something is obviously confusing, but I’ve tried to put proper comments in the book whenever any reviewer asked a question about the code.

Anyway – I expect it will be in PDF form in only a few weeks! I’m looking forward to hearing what people think of it.

On a funny note, I was working on something in work recently, and was trying to figure the best way to do it, when I suddenly remembered I’d written a whole chapter on it, so went and read what I’d written! I’ll be keeping a copy of the book on my own shelf 😉

This kind of thing is always happening to me – I would need to solve some problem (hooking an OKI B2200 printer to Linux over Samba, for example), go searching for the answer, and find that I’d written the solution for it a year or two previously…

By the way, KFM 1.4 will be released next week. It will be the last 1.x version. We (Benjamin and myself) are starting a total rewrite after that, which will become KFM 2. It’s going to be massive!

EDIT: 2009-09-18 Wow, that was quick! The book is already available to pre-book

jQuery 1.3 With PHP: chp7, image manipulation

I’ve submitted chapter 7 of jQuery 1.3 with PHP to Packt, which involves image manipulation. The editor I build in that chapter allows you to non-destructively manipulate an image in the most commonly needed ways – resize, rotate and crop.

The idea is that when you upload an image, it’s usually not yet right to include in a website. People tend to upload massive photos (3000×2000 or so) and resize it down using the <img> attributes, which is the wrong way to do it (see here for a solution to that particular problem).

However, once you’ve resized an image down, you can’t change it back.

The solution is to make copies of the image with your manipulations applied to them. That lets you make multiple versions of the same image.

But again, there’s the problem that if you change your mind about the original image, you can replace that, but the others all need to be redone.

Yet another problem is that unless you’ve kept records, there’s no link from the new images back to the original, so if you need to make space on the server by removing files that might not be in use anymore, you can’t be certain what thumbnails are still relevant and what are not.

The solution is to not actually create copies, but to record the changes applied to the original image in the URL of your manipulated image. When the server is asked for those URLs, it runs the manipulations on the original image and gives you back the new image. Of course, we will cache the new manipulations so this doesn’t need to be done every time, but this now allows you to replace the original image, then clear the cache, forcing all the variants of it to refresh, without you needing to do it again.

What this means, is that when the manipulation is recorded in the URL, no new copy is actually created until some browser actually requests it. This means that you can periodically clear your old thumbnails, safe in the knowledge that if they were still relevant, they will be recreated from the archived originals automatically the next time they’re needed.

Enough talk.

demo

This is, as usual, just a demo. It’s not designed to be impressive, but just to show how to do manipulations.

A permanent URL is provided, in the same manner as google maps – it updates itself as you manipulate it. To see the actual cropped, resized and rotated image, try opening that permanent URL in a different tab.

The GUI here is a means to an end (the permanent URL). In your own CMS, you might force a certain width/height for uploaded images automatically using the URL for example.

The example image I manipulated in the chapter is the IMG_0134.JPG in chp7. Try rotating, resizing, and cropping (drag your mouse on the image).

example:

Little thing to note about that URL – there’s no query indicator. Standards-compliant browsers treat the ‘?’ mark in a URL as an indication that the result should never be cached, but that would be pretty expensive for the server, so we remove that. The get.php file rebuilds the query from the $_SERVER['REQUEST_URI'] and sends out the manipulated image with caching headers.

The graphics manipulation was done using Imagick, which is a PECL extension that allows PHP to run ImageMagick functions internally.

In Fedora, you can install Imagick with yum install php-pecl-imagick. In CentOS, follow these instructions.

CentOS users might have a problem with the latest Imagick (2.2.2), so change the pecl install imagick line to pecl install imagick-2.2.1.

download the demo

Make sure to edit the images_libs.php file to point to your own image repositories. The images don’t need to be in a web-accessible directory.

I’ve a bit of work to do now, and then I’ll be applying the tricks in this chapter to our own CMS, WebME.

jQuery 1.3 With PHP: Calendars

I was supposed to write about Datatables for chapter 6 of jQuery 1.3 with PHP, but the website of the plugin I was going to use (http://www.datatables.net/) was down for about a week, and so I wrote about Calendars instead.

I used Red3‘s jquery-week-calendar plugin for a recent project in work, and was so impressed I really had to write about it.

In chapter 6 of the book, I’ll walk through how to build a simple calendar, including creation and editing of events, and including once-off and recurring events.

demo

The demo is a session-based calendar, which records only for the duration of your browser session. It’s for demo purposes only, obviously. If you want to use it in a larger project, you would need to adapt the PHP so that it records to a database or files or something.

Download

Here’s an image of it in use:

fig_6_0

Only four or so chapters left and then I’m done with the hard part. After that, is rewrites, then you can all throw your money at me.

error logger, mantisated

The plugin architecture for Mantis is not yet mature, so I’ve bypassed it in this. Instead, this script will inject issues directly into the Mantis database.

The following script will load up all errors aggregated with the last post’s script, and will add them as Mantis issues (or update existing issues if found).

<?php
$t=time();
$project_id=6;
$error_urls=array(
  'http://the.url/error_checker/?password=abcdefg&maxlines=5000&last_date_read='.($t-3600)
);

require 'config_inc.php';
$db=new PDO($g_db_type.':host='.$g_hostname.';dbname='.$g_database_name,$g_db_username,$g_db_password);
$db->query('SET NAMES utf8');

foreach($error_urls as $eu){
  echo $eu."\n";
  $errors=json_decode(file_get_contents($eu));
  foreach($errors as $err){
    $md5=addslashes($err->md5);
    $q=$db->query("select id,summary from mantis_bug_table where summary like '$md5 %' limit 1");
    $r=$q->fetch(PDO::FETCH_ASSOC);
    $cnt=(int)$err->count;
    if($r){
      $id=$r['id'];
      $cnt=preg_replace('/.* \(([0-9]*)\)/','\1',$r['summary'])+$cnt;
      $db->query("update mantis_bug_table set status=10,summary='$md5 ($cnt)' where id=$id");
      $btext=addslashes($err->log);
      $db->query("insert into mantis_bugnote_text_table values(0,'$btext')");
      $btext_id=($db->query('select last_insert_id() as id')->fetch());
      $btext_id=(int)$btext_id['id'];
      $db->query("insert into mantis_bugnote_table set bug_id=$id,bugnote_text_id=$btext_id,date_submitted=now(),last_modified=now()");
    }
    else{
      $db->query("insert into mantis_bug_table set date_submitted=now(),summary='$md5 ($cnt)',project_id=$project_id");
      $id=($db->query('select last_insert_id() as id')->fetch());
      $id=(int)$id['id'];
      $db->query("insert into mantis_bug_text_table set id=$id,description='".addslashes($err->error)."',additional_information='".addslashes($err->log)."'");
      $btext_id=($db->query('select last_insert_id() as id')->fetch());
      $btext_id=(int)$btext_id['id'];
      $db->query("update mantis_bug_table set bug_text_id=$btext_id where id=$id");
    }
    $db->query("update mantis_bug_table set last_updated=now() where id=$id");
  }
}

Note the bold lines – the first indicates what Mantis project to place the issue under. In my case, I created a new project named “httpd errors”, which had the ID 6. The second is an array of URLs pointing to where the error aggregators can be found. In this case, the Mantis injector is going to be called from cron every hour, so the URL includes a time limit looking for errors only in the previous hour (3600 seconds).

webme r95 packaged

I’ve packaged WebME revision 95, and it is available from the WebME Downloads page.

Improvements include:

  • Plugin architecture. Developer documentation
  • Sample plugins:
    • Banners: provide site-wide or page-specific banners; randomly rotate multiple banners.
    • Forms: show contact forms on your site. Can be templated – documentation to be written, but simple usage should be obvious.
    • Image Gallery: turn a directory of images into a gallery automatically.
    • Mailing List: written by Conor; accept subscriptions on your site; bulk email them.
    • Panels: lets you edit a section of HTML which is visible on every page of your site.
    • Polls: let your readers vote for stuff.
  • Some bug-fixes.

I’ve added a boat-load of new themes to the free site builder, so please feel free to create a site and try it out.

update on Me

Quick update of what’s happening in the world of Kae.

I’ve been busy recently with a new project in the office, making an ultra-WebME system which can be used by companies who are not web designers, to offer their clients “pre-packaged” websites. I may elaborate on that in a few weeks once the pilot study is out of the way.

I haven’t touched the KFM file manager project in ages, and recently realised that it’s because I’m just not happy with it anymore. It’s monstrously complex now, and just not flexible enough for the changes I want to build into it. So, I’m seriously thinking of rewriting it completely, or building a new file manager project to compete with it.

WebME is progressing quickly. The plugins architecture is damned easy to use, if I do say so myself. So much so that Conor wrote a mailing-list plugin before I even got to announce the plugin system. To try it out, get the Subversion copy of WebME, and also the subversion copy of the existing plugins (svn checkout http://webworks-webme.googlecode.com/svn/ww.plugins/) and create a symbolic link from ‘ww.plugins’ in the root of your WebME installation to the checked-out ww.plugins directory. Then in the /ww.admin section, go to Site Options > Plugins and try some stuff. I’ll be writing a proper tutorial on how to create a plugin. Probably today.

I started learning piano at the beginning of last month and am proud to say that I appear to be learning at a prodigious rate. This is probably because I can already play well on a number of other instruments. Last tune I learned was Ecossaise in E Flat by Beethoven (WoO 86), played here by Matt Baker:

Before that was I’ll Take You Home Kathleen, played here by Dave Seddon on steel guitar (couldn’t find a piano version that wasn’t ruined by people singing over the music 😉 ):

I’m still in quite a lot of pain since last week’s operation, but hopefully it will ease off over the weekend, as I have the next chapter of my book to submit.

jQuery 1.3 With PHP

Last year, I did a few reviews of books by Packt Publishing. This year, they got their own back – Packt have asked me to write a book for them called jQuery 1.3 with PHP.

The book is aimed at experienced PHP programmers who are interested in adding a bit of client-side magic to their sites. jQuery is used because it’s damned powerful, and you can get some very cool results without too much work.

The server-side code will only be described, and examples will be provided for illustrative purposes – the real target of this book is the client-side and how it interacts with the server.

The chapter list has been agreed, although there may be scope for adjustments as the book progresses. Here’s what we have:

  1. jQuery and PHP
  2. Quick Tricks
  3. Tabs and Accordions
  4. Form validation
  5. Image and file management
  6. Data-tables
  7. AJAX-based form submission
  8. Drag/Drop
  9. Optimisation

The chapters are a little more exciting than you may think. For example, Drag/Drop will cover cool tricks like cropping/resizing images, and Data-Tables will include inline editing of the content of the tables.

The time-table suggests that the book may be completed by late August – not sure when it will be out, but I’m guessing October or so.

As a project for the book, I’ll be writing an open-source newsletter system, which will demonstrate all of the code described in the book.

hosting multiple sites from the same CMS engine

I posted about webwork.ie‘s free website engine a few days ago. In the comments, Mickster asked how he would go about doing it himself.

I haven’t studied how other engines do it, but here’s how I do it.

First off, some benefits to sharing the CMS across separate sites:

  • Reduced resource usage. Because a single PHP engine is used, it is easier to optimise using RAM-disks, PHP caching, and other optimisations.
  • Easier upgrades – upgrade one system, upgrade them all!
  • Easier bug-fixing. One of the banes of my life is discovering a bug in a CMS that you know exists in at least ten other instances of that CMS. Now, you fix the bug in one place, and it’s fixed everywhere!

Convinced yet? Of course you are. Here’s how you do it.

First, separate all site-specific files from your engine files. To do this, you need to strictly keep your uploaded files and site-specific CSS in separate from your executable PHP. After doing this step, you should be able to clearly point out directories in your CMS and say “those are the engine’s executables and other resources, these are the design files and other uploadables which are site-specific.”

Second, all site-specific resources should be served through a script. The reason for this is that we are going to be moving the files away from the perceived directory that they’re in. Instead of, say, a web root of /home/webme/public_html/ with an image located at /home/webme/public_html/i/image.jpg, you might have the image located at /home/webme/sites/webme.eu/i/image.jpg, and another image from a different site located at /home/webme/sites/an-other-site.com/i/image.jpg. The choice of which image to show when /i/image.jpg is referenced depends then on the domain-name the browser requested the file from.

Then you need to over-ride the config at the time of its request. In the WebME CMS, the config file is located at /.private/config.php. What we want is to replace that with a “proxy” config file which, when included, checks the domain name and includes the real config file.

So how does the proxy config know where the real one is located? the way I handle this is to have a directory named after the site, located in /home/webme/sites/$NAME. If, for example, blah.webme.eu or www.blah.webme.eu is requested, you strip off any leading www. strings and trailing webme.eu strings with a regexp, and check to see if the config (/home/webme/sites/blah/config.php) exists. If so, include it.

To handle aliases, for example, if you wanted www.blah.com to load the blah.webme.eu site, you create a directory /home/webme/sites.aliases/$NAME, where $NAME (blah.com) is a symbolic link pointing to the correct directory.

It’s not a difficult trick, but it works.

Here’s my proxy config file:

Here is a copy of the proxy file that I use in webme.eu’s multi-user engine.

<?php
$host=preg_replace('/^www\.|\.webme.eu$/','',strtolower($_SERVER['HTTP_HOST']));
$cfile='/home/webme/sites/'.$host.'/config.php';
if(!file_exists($cfile)){
        $cfile='/home/webme/sites.aliases/'.$host.'/config.php';
        if(!file_exists($cfile)){
                header('Location: http://webme.eu/');
                exit;
        }
}
require $cfile;
define('CONFIG_FILE',$cfile);

webme-mu: create your own website

I’ve just finished the first version of the site creator. You can create your own website using this wizard.

This involved a bit of work on my part – I needed to separate personal files (images and other downloadables) from internal files (scripts and other resources), and ensure that personal files could be read from anywhere on the server, not necessarily from a web-accessible directory.

Then, I needed to write the site generator to write config files automatically.

Then, WebME needed to be hacked to load the correct config file, based on the domain name requested.

This has worked. I now have two sites running on that server (http://verens.webme.eu/ and http://webme.eu/), both of which use the same engine instance. The only things that are separate are their databases and their personal files.

The best thing about this was that it was possible to do this without compromising the structure of the downloadable version of WebME. The downloadable version and the multi-user version use exactly the same source code. The only difference is in the config file. In the case of the multi-user version, when the config file is loaded, it acts as a proxy, loading the correct site-specific config file.

After all that work, I need a drink! Please, give the site a chance, and report any problems you come across.