dom111.co.uk http://www.dom111.co.uk/blog Move along. Nothing to see here. Thu, 18 Feb 2010 15:38:27 +0000 http://wordpress.org/?v=2.9.2 en hourly 1 XML Entities in PHP http://www.dom111.co.uk/blog/coding/xml-entities-in-php/224 http://www.dom111.co.uk/blog/coding/xml-entities-in-php/224#comments Mon, 15 Feb 2010 20:34:35 +0000 dom111 http://www.dom111.co.uk/blog/?p=224 Because htmlentities() doesn’t even come close.

This small file contains 4 functions (2 of which are taken from the PHP manual, credit given!) which will allow you to encode and decode entities from ASCII/unicode strings in either decimal or hexadecimal format for use in valid XML documents.

The xml_entity_decode() function accepts an optional second parameter to allow non-standard XML entities (that may have been specified in your schema) in the format:

array(
  // 'entity' => 'char'
  'amp' => '&',
  'lt' => '<',
  'gt' => '>',
  'apos' => '\'',
  'quot' => '"'
)

Example usage:

include('funcs.xmlentities.php');
 
$s = '<strong>This</strong> should be safe, but don\'t assume!<br/>';
print '<Field>'.xmlentities($s).'</Field>';
// outputs: <Field>&lt;strong&gt;This&lt;/strong&gt; should be safe, but don&apos;t assume!&lt;br/&gt;</Field>

You can get the script here, or there’s a demo here too.

]]>
http://www.dom111.co.uk/blog/coding/xml-entities-in-php/224/feed 0
Dropdownify – Minimal effort dropdown http://www.dom111.co.uk/blog/coding/dropdownify-minimal-effort-dropdown/218 http://www.dom111.co.uk/blog/coding/dropdownify-minimal-effort-dropdown/218#comments Wed, 27 Jan 2010 12:19:38 +0000 dom111 http://www.dom111.co.uk/blog/?p=218 So recently I was asked to change a navigation style of an existing site to drop-down menus.

Simple, I thought, just use one of the many existing drop-down plugins. I tried many, but most seemed to use hardcoded styles and I had a few problems (some of which I encountered again, writing this).

So I’ve made this, I think it’s fairly robust, but I’m sure there’ll be problems with embedded objects (flash) and select boxes (in <= IE6), but for my needs, it sufficed, so I thought I'd share, in case anyone else needs a simple script to manage drop-downs.

To use, create a nest of elements like this:

<ul id="top">
  <li>
    <ul>
      <li></li>
    </ul>
  </li>
</ul>

or something similar (any elements, should work) and call:

// jQuery:
$('ul#top').dropdownify();
 
// mootools
$('top').dropdownify();

Which should create a simple drop-down.

There are a couple of examples, one for jQuery and one for mootools, and the files can downloaded here and here.

I did encounter a problem with IE, mainly due to z-index faults, so with HTML code like the following:

<div class="nav-wrapper">
  <ul id="top">
    <li>
      <ul>
        <li></li>
      </ul>
    </li>
  </ul>
</div>

I used the following CSS:

div.nav-wrapper,
div.nav-wrapper ul,
div.nav-wrapper ul li {
  position: static;
  z-index: 100;
}
]]>
http://www.dom111.co.uk/blog/coding/dropdownify-minimal-effort-dropdown/218/feed 0
Breaking down large CSV files http://www.dom111.co.uk/blog/coding/breaking-down-large-csv-files/214 http://www.dom111.co.uk/blog/coding/breaking-down-large-csv-files/214#comments Thu, 17 Dec 2009 13:53:51 +0000 dom111 http://www.dom111.co.uk/blog/?p=214 Today I received a 45Mb CSV file for importing into a database… Needless to say the application we were importing to didn’t seem to like the size of the file, for what ever reason… So I knocked up a quite bash script to create smaller ‘chunks’ defined as a number of lines, to make importing simpler.

I’m sure there’s many way in which is can be simplified, so if you know any I’d like the contributions!

It’s run like this:

$ ./csv-chunk.sh large-data.csv 5000

The first argument being the filename and the second argument the maximum number of lines for each ‘chunk’. From that 45Mb megalith, 38 files of around 1.2Mb were produced which didn’t seem to break the other end!

Here’s the script:

#!/bin/bash
 
function help {
  echo "Usage:"
  echo "  $0 <csv filename> <number of lines>=5000"
  exit 1
}
 
if [ $# -eq 0 ]; then
  help
fi
 
if [ $# -eq 1 ]; then
  chunk=5000
else
  chunk=$2
fi
 
file=$1
 
if [ ! -e $file ]; then
  echo "File $file not found!"
  exit 5
fi
 
header=`head -n 1 $file`
max=`cat $file | wc -l`
x=1
 
echo "Breaking down $file ($max lines into $chunk lined files)"
 
for (( i=1; i<=$max; i+=$chunk )); do
  chunkfile="chunk-$x-$file"
 
  if [ -e $chunkfile ]; then
    echo "$chunkfile already exists!"
    exit 2
  fi
 
  `touch $chunkfile`
  echo $header > $chunkfile
 
  start=`expr $i + 1`
  end=`expr $i + $chunk`
 
  `sed $start,$end\!d $file >> $chunkfile`
 
  x=`expr $x + 1`
done
 
echo "Created $x files"
exit 0
]]>
http://www.dom111.co.uk/blog/coding/breaking-down-large-csv-files/214/feed 0
jQuery Message – Letting the user know what’s going on http://www.dom111.co.uk/blog/coding/jquery-message-letting-the-user-know-whats-going-on/209 http://www.dom111.co.uk/blog/coding/jquery-message-letting-the-user-know-whats-going-on/209#comments Mon, 14 Dec 2009 09:40:14 +0000 dom111 http://www.dom111.co.uk/blog/?p=209 Screenshot

Recently I’ve seen a few implementation of Growl in Javascript and basically just thought I’d have a go too. Everyone’s doing it, or so it seems!

This simple implementation is styled using pure CSS and you should be to easily modify it to suit your needs!

I’ve set up a demo page and the files can be grabbed from here.

]]>
http://www.dom111.co.uk/blog/coding/jquery-message-letting-the-user-know-whats-going-on/209/feed 0
Apache, Subversion and favicon.ico http://www.dom111.co.uk/blog/apple/apache-subversion-and-favicon-ico/205 http://www.dom111.co.uk/blog/apple/apache-subversion-and-favicon-ico/205#comments Tue, 20 Oct 2009 11:20:07 +0000 dom111 http://www.dom111.co.uk/blog/?p=205 I discovered a strange error in my apache logs today:

[Tue Oct 20 11:04:10 2009] [error] [client 12.34.56.78] (20014)Internal error: Can't open file '/.../svn/repositories/favicon.ico/format': No such file or directory
[Tue Oct 20 11:55:55 2009] [error] [client 12.34.56.78] Could not fetch resource information.  [500, #0]
[Tue Oct 20 11:55:55 2009] [error] [client 12.34.56.78] Could not open the requested SVN filesystem  [500, #2]
[Tue Oct 20 11:55:55 2009] [error] [client 12.34.56.78] Could not open the requested SVN filesystem  [500, #2]

Most of my Google searches returned issues where people couldn’t view their repositories, but I could see mine fine…

Then I looked at the error messages again and noticed it was looking for a repository called favicon.ico. A quick Google later and I found this page:

http://www.trilithium.com/johan/2005/02/no-favicon/

Adding the suggested items to my Apache conf fixed the problem!

]]>
http://www.dom111.co.uk/blog/apple/apache-subversion-and-favicon-ico/205/feed 0
PHP CSV Reader http://www.dom111.co.uk/blog/coding/php-csv-reader/201 http://www.dom111.co.uk/blog/coding/php-csv-reader/201#comments Wed, 07 Oct 2009 19:08:22 +0000 dom111 http://www.dom111.co.uk/blog/?p=201 I’ve never really built a definitive CSV reader and end up building a quick implementation of one any time I need one.

But after working on the chunk script I decided that next time I build a CSV class I’d do it properly.

This is the result:

  <?php
  require('class.csv.php');
 
  header('Content-type: text/plain');
 
  $csv = new CSV('test.csv');
 
  while ($row = $csv->read()) {
    print_r($row);
  }

There’s an information page here, and the script is here.

]]>
http://www.dom111.co.uk/blog/coding/php-csv-reader/201/feed 0
jQuery Ajaxify – Update http://www.dom111.co.uk/blog/coding/jquery-ajaxify-update/191 http://www.dom111.co.uk/blog/coding/jquery-ajaxify-update/191#comments Thu, 24 Sep 2009 14:17:56 +0000 dom111 http://www.dom111.co.uk/blog/?p=191 I’ve been doing more work on the jQuery AJAXify plugin, it’s now a lot more robust (I think…) and I’ve squashed a few bugs that were in the previous version (with help from Andrea Battaglia) along with adding in a few new features (with their own bugs no doubt!).

Theres an updated test page and as ever a direct link to download here.

Check out the test page to see the new features!

Edit: Further updates, all links have been updated to version 0.3b. Added (and documented existing) callbacks as requested by Sebioff! And a further fix for the ‘append’ option. Also fixed IE6 compatibility.

Further Update: Another update after the comment from David Lee about $(‘form’).serialize();

Another Further Update: I have set up a Google Code repository for this plugin, which states that this code is released under the MIT license.

]]>
http://www.dom111.co.uk/blog/coding/jquery-ajaxify-update/191/feed 16
DNS Issues http://www.dom111.co.uk/blog/coding/dns/dns-issues/189 http://www.dom111.co.uk/blog/coding/dns/dns-issues/189#comments Thu, 24 Sep 2009 08:08:22 +0000 dom111 http://www.dom111.co.uk/blog/?p=189 Looks like this blog’s been down for a few days…

I’ve moved my DNS over to 123-reg and have had a few issues getting all the DNS records to work as expected…

Hopefully I’ve fixed it now…

]]>
http://www.dom111.co.uk/blog/coding/dns/dns-issues/189/feed 0
CakePHP: Select Box Pagination http://www.dom111.co.uk/blog/coding/cakephp-select-box-pagination/182 http://www.dom111.co.uk/blog/coding/cakephp-select-box-pagination/182#comments Thu, 27 Aug 2009 12:40:54 +0000 dom111 http://www.dom111.co.uk/blog/?p=182 Using CakePHP’s built in pagination system has saved me so much time in my current day job, but the latest designs I’m working on have drop-down box style pagination, as it’s possible to get many pages of results.

To change the named parameters in the current URL I’ve created this small javascript function that will amend the URL:

/**
 * setURL
 *
 * Modifies the current URL and redirects the browser
 *
 * @param string key The name of the parameter to set
 * @param mixed value The value to set the parameter to
 * @return void
 * @author Dom Hastings
 */
function setURL(key, value) {
  // set up the url separators
  var separator = {
    // site.url/controller/action/key1:value1/key2:value2
    'key': '/',
    'value': ':'
  }
 
  // get the current url
  var url = window.location.href;
  // check if the specified key already exists
  var exists = url.indexOf(separator.key + key + separator.value);
 
  // if it does
  if (exists > -1) {
    // find the next separator.key
    var last = url.indexOf(separator.key, exists + 1);
 
    // if there is one
    if (last > -1) {
      // replcae the existing value with the one passed
      url = url.substr(0, exists) + separator.key + key + separator.value + escape(value) + url.substr(last);
 
    // if not
    } else {
      // just append it
      url = url.substr(0, exists) + separator.key + key + separator.value + escape(value);
    }
 
  // if it's not already in there
  } else {
    // if the URL doesn't end with a separator.key
    if (url.substr(-1) != separator.key) {
      // append it
      url += separator.key;
    }
 
    // append the value
    url += key + separator.value + escape(value);
  }
 
  // set the url
  window.location.href = url;
}

Coupled with the following code to my view:

<!-- Items per page: -->
<select onchange="setURL('limit', this.value)">
  <option value="10"<?=($params['named']['limit'] == '10') ? ' selected="selected"' : ''?>>10</option>
  <option value="20"<?=($params['named']['limit'] == '20') ? ' selected="selected"' : ''?>>20</option>
  <option value="50"<?=($params['named']['limit'] == '50') ? ' selected="selected"' : ''?>>50</option>
  <option value="100"<?=($params['named']['limit'] == '100') ? ' selected="selected"' : ''?>>100</option>
</select>
 
<!-- Page: -->
<select onchange="setURL('page', this.value)">
<?php for ($i = 1; $i <= $paginator->counter(array('format' => '%pages%')); $i++): ?>
  <option value="<?=$i?>"<?=($params['named']['page'] == $i) ? ' selected="selected"' : ''?>><?=$i?></option>
<?php endfor ?>
</select>

Hopefully it’ll help anyone else deal with a similar problem!

Note: If there’s a simpler, more accessible way to do it, I’d really like to know!

]]>
http://www.dom111.co.uk/blog/coding/cakephp-select-box-pagination/182/feed 0
CakePHP: Components, redirect fail (On my part…) http://www.dom111.co.uk/blog/coding/cakephp-components-redirect-fail-on-my-part/171 http://www.dom111.co.uk/blog/coding/cakephp-components-redirect-fail-on-my-part/171#comments Wed, 26 Aug 2009 19:58:46 +0000 dom111 http://www.dom111.co.uk/blog/?p=171 I’ve been working on a CakePHP project lately and created a small component which was only needed in one of my controllers:

class CounterComponent extends Component {
  var $components = array(
    'Session'
  );
 
  function i() {
    if ($this->Session->check('Counter.i')) {
      $i = ($this->Session->read('Counter.i') + 1);
 
    } else {
      $i = 0;
    }
 
    $this->Session->write('Counter.i', $i);
 
    return $i;
  }
 
  function clear() {
    $this->Session->delete('Counter.i');
  }
}

It simply kept track of a number over the life of the current session and incremented it each time it was accessed. I did’t think it would interfere in my other controllers, and it didn’t until I tried to perform a simple redirect later on in the app:

  function edit($id) {
    if (!empty($this->data)) {
      // process it
      $this->Customer->id = $id;
 
      $this->Customer->save($this->data);
 
      $this->redirect(array(
        'controller' => 'customers',
        'action' => 'view',
        $id
      ));
 
    } else {
      $this->data = $this->Customer->find('first', array(
        'id' => $id
      ));
 
      extract($this->data);
    }
 
    $this->set(get_defined_vars());
 
    $this->render('form');
  }

That code seemed simple enough, but each and every time it was run, I’d be sent to /customers/edit, instead of /customers/view/1.

WTF? Cake is losing my ids?

So I tried changing the redirect to a string:

      $this->redirect('/customers/view/'.$id);

No difference, still redirects to /customers/edit. Ok fine. Lets try a full URL:

      $this->redirect('http://www.google.co.uk/');

Serisouly. Still? All this happened over a series of a couple of days, each session of codingbanging my head against a brick wall leaving me more frustrated. I got mad I created a TestsController with an action test which exhibited the same behaviour… (But only after I’d moved everything into the AppController, whilst franticly trying everything… *sigh*)

After many visits to the CakePHP documentation I decided to re-investigate the source code and see if I had missed anything. The Controller::redirect() function contains this code:

		$response = $this->Component->beforeRedirect($this, $url, $status, $exit);
 
		if ($response === false) {
			return;
		}
		if (is_array($response)) {
			foreach ($response as $resp) {
				if (is_array($resp) && isset($resp['url'])) {
					extract($resp, EXTR_OVERWRITE);
				} elseif ($resp !== null) {
					$url = $resp;
				}
			}
		}

“But that’s fine!”, I thought, “I don’t even have a beforeRedirect() function in my component, and surely the class I’m extending will just return null.” Oh dear. Assumption. There it is, done now.

// Component::beforeRedirect
	function beforeRedirect(&$controller, $url, $status = null, $exit = true) {
		$response = array();
 
		foreach ($this->_primary as $name) {
			$component =& $this->_loaded[$name];
 
			if ($component->enabled === true && method_exists($component, 'beforeRedirect')) {
				$resp = $component->beforeRedirect($controller, $url, $status, $exit);
				if ($resp === false) {
					return false;
				}
				$response[] = $resp;
			}
		}
		return $response;
	}

Crap. It returns an empty array, which the redirect() function will use because it isn’t null, which will redirect to the current controller/action but strip out the id.

Lesson: Always, ALWAYS, create a base component to extend, or, alternatively, just read the fricking manual properly.

TL;DR: I failed at creating a CakePHP component. Fix: class MyComponent extends Object {} instead of class MyComponent extends Component {}.

]]>
http://www.dom111.co.uk/blog/coding/cakephp-components-redirect-fail-on-my-part/171/feed 1