21 May

jQuery 1.3 With PHP: tiny file manager

For chapter 5 of my book, jQuery 1.3 with PHP, I wrote a small file manager. It doubles up as a file selector.

demo

You would use this in an admin area where it is necessary to select files or directories, and you’d also like to create/rename/move those things around.

fig_5_10

Try a few things on it – change the selection in the two select-boxes, move a few things around, etc. I think it’s useful and nicely compact.

You can download it here along with the examples that lead up to the finished thing. You will also need a copy of jQuery and uploadify.

To install, just link to your copies of the above libraries, correct the $base variable in the .php file, and in the .js file, change ../jquery.uploadify-v1.6.2/ (in the fm_uploadFileSetup function) to wherever you installed it.

$base should point somewhere outside of the web root, as the file manager does not discriminate between innocent files such as test.txt and potentially harmful files such as hackme.php. A downloader is included which allows any files uploaded through this to also be downloaded through it.

14 May

iphone

Okay, I succumbed to the temptation and got one.

A number of annoyance have presented themselves already, in just the few hours that I’ve owned it.

First off, when you get the thing, it’s in a fancy box with all the bits and pieces in it. I took all of the bits out, and found a nice rectangular cardboard box which when opened, held the documentation. I took out the documentation and read through it, discarding the box. Couldn’t figure out how to install the SIM card into the machine, as the documentation did not mention it anywhere. After an hour or so of puzzling over it, I finally noticed that the documentation box, which I had discarded, had a weird little diagram on it, which when deciphered, explained how to do it. Way to go Apple – in this case, I did RTFM, but TFM didn’t have the instructions I needed.

Secondly. After going through the jumpy-hoopy thing of filling in a form and waiting 24 hours to be allowed to own the machine (for some reason) and then waiting another hour for the receptionist at the shop to finally get through to O2 to activate the SIM, I was just picking up everything and the guy said “ok, now you just need to activate it through iTunes”. Excuse me?? It’s a fucking phone! I can’t get iTunes running on any of my computers at home anyway because I don’t have anything that runs Windows or Mac! I spent hours trying to get Wine to install iTunes, but finally had to give up and do it on an old WinXP machine in the office the next day.

Then, I wanted an SSH client for the thing. There is a cool store for the iPhone called appStore, and there were a number of SSH clients in there. In order to get one of them, though, you need an account and some cash.

First off, I tried to just create an account. This went okay, up until the point where iTunes asked what my credit card number was. I don’t have a credit card, and don’t want one. After a while, I figured out that the only way to get an account for free (or at least, without giving Apple credit card details), is to apply to download an app which is specified as free – for some reason, in that case, Apple adds a “none” option to the list of payment methods.

So I had an account, but still couldn’t pay for anything. Apple claim that they accept PayPal, and even supply instructions on how to do it. Unfortunately, it falls down immediately, because step two says to click Edit Credit Card or Add Credit Card in your iTunes account page, but those links don’t exist! Maybe they exist if there is already a credit card attached to the account, but that defeats the entire purpose!

But it’s a nice phone, really.

09 May

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).

09 May

error aggregator script

I mentioned an idea a few days ago, where a script would be used to read error logs and log them to Mantis (or some other bug tracker).

I’ve written the first part. [error_checker-20090509.tar.bz2]

When run, the script checks your HTTP error log and reads the last n lines (set using the config.php or add “?maxlines=n” to the URL).

It then aggregates xdebug errors, which tend to run over a few lines, and then lumps all similar errors together, counting the occurrences.

Finally, the lot is printed to screen as a JSON dump, which can be read by JavaScript (through eval or JSON.decode)or by PHP using json_decode.

The program is protected by password (set in config.php) which can be added to the URL or sent as a POST variable.

Oh – you can also tell it to only send back errors that happened after a set unix_date (get it using time in PHP).

Example call:
http://the.url/error_checker/?password=abcdefg&maxlines=5000&last_date_read=1241867256

My plan is to have one of these scripts installed on every machine that I host, and to call it every now and then and add the results to a Mantis bug tracker, using the MD5 of the error as a subject line along with the number of occurrences (you could say that the higher-numbered errors should be fixed quicker because they happen more often).

05 May

jQuery 1.3 With PHP: chapter 4

Chapter 4 (of my book jQuery 1.3 with PHP for Packt) was on form validation. I put up the demos in the usual place.

Of particular interest is this one. It has a number of points, including two that I haven’t seen anywhere else yet.

  • remote checking of email addresses against the server database (kae@verens.com is registered, for example).
  • the Country drop-down is a new trick which I’ll explain in a moment.
  • the City field acts as an auto-suggest based on what’s selected in Country (select Ireland and type a letter in there).
  • the form itself does not have an action parameter. that’s the second trick.

Optimising Large Select-boxes

In the example, I’ve only mentioned a few countries, but in reality, you’d use the full list. If you look at the source of the form, you’ll see that actually, only Ireland is mentioned. This is because it does not make sense to always print tens of KB of HTML if most of it will not be used – what if the form is for an irish company and it is not expected that the country would /need/ to change?

The solution is to only load the country list if the select-box is clicked.

This also applies to other large select-boxes. I’ll be using this trick in-house for forms that always slow down when they’re rendering select-boxes – especially db-sourced select-boxes.

Action-less Forms

This is an attempt to get away from captchas, which are getting increasingly difficult for humans to solve, and easier for computers.

The idea is that the form is rendered with no action parameter, and then jQuery retrieves the needed parameter via AJAX 1.5 seconds later. The server records the time the form was rendered, and if the jQuery request comes in before 1.5 seconds, then it’s a spam-bot and will not be allowed to post. If the form is submitted in less than 10 seconds, or greater than 10 minutes, or if it’s submitted without loading the form and action in the first place, then it’s a spam bot and will not be allowed to post.

I’m pretty confident this will slow down spam a bit. It can’t possibly /solve/ it, but it will make it more difficult for spam-bots, yet humans will not notice anything out-of-the-ordinary at all.

The source is of course available.

02 May

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.