Shortlink

Avoiding hidden form fields

Hidden fields in a form can be useful, but they can also pose a huge security risk. Take an example of a web page which allows a user to edit a customer’s details.

<form>
  <input type='hidden' name='customer_id' value='abc123'/>
  <input type='text' name='first_name'/>
  ...
  ...
  <input type='submit' value='Save'/>
</form>

Using a browser add-on such as Firebug it’s very easy for a user to change the value of that customer_id field on the fly. It’s then possible, just by changing the value of the id field to the id of another customer, to overwrite one customer’s details with another. You can see how this might be a problem!

The simplest solution to this problem is to store the hidden field in the session data instead of passing a hidden field, like so:

$_SESSION['customer_id'] = 'abc123';

Then, when performing your save you write something like this:

$customer = new Customer;
$customer->retrieve($_SESSION['customer_id']);
$customer->import_form_data();
$customer->save();

Hurrah, no chance of getting the wrong id for the customer. But wait, what happens if the user opens two different browser windows, each editing a different customer? Opening the second browser window will overwrite the customer_id in the session data, and saving on either window will overwrite the data of the second customer.

To get around this I store the relevant “hidden” data for every form in a separate session variable and pass a token to the form. I have written a class and associated functions to do this. Using our example of editing a customer the code now looks like this:

 
$token = register_form_state(array('customer_id' => $customer->id));
 
echo <<<END
 
<form>
  <input type='hidden' name='token' value='$token'>
  <input type='text' name='first_name' value='$customer->first_name'>
  ...
  ...
</form>
END;

Now, when the form is posted, I can retrieve the data like so:

 
$data = get_form_state($_REQUEST['token']);
 
$customer = new Customer;
$customer->retrieve($data->customer_id);
$customer->import_form_data();
$customer->save();

Shortlink

Asserting that an array contains another array in PHPUnit

I needed to test whether one array contained a subset of another array in PHPUnit. There’s no built-in function for that so if you have a similar need feel free to use the code below:

 
 
class test extends PHPUnit_Framework_TestCase
{
 
 
    public function testArrayComparison()
    {
 
        $needle = [
            'a'        => [
                'aa'    => [
                    1, 2, 3
                ]
            ],
            'b'        => 'b',
            'c'        => 1,
        ];
 
        $haystack                 = $needle;
        $haystack['a']['bb']      = [4, 5, 6];
        $haystack['d']            = 666;
 
        print_r($needle);
        print_r($haystack);
 
        $this->assertArrayContainsArray($needle, $haystack);
 
    }
 
 
    protected function assertArrayContainsArray($needle, $haystack)
    {
        foreach ($needle as $key => $val) {
            $this->assertArrayHasKey($key, $haystack);
 
            if (is_array($val)) {
                $this->assertArrayContainsArray($val, $haystack[$key]);
            } else {
                $this->assertEquals($val, $haystack[$key]);
            }
        }
    }
}

Shortlink

Ruby DataMapper aliased associations

In Ruby’s DataMapper ORM you can easily associate one type of object with another, e.g. an Image can have many Tags. For the most part DM takes care of the issue of pluralization, ie. if your tag object is Tag then the associated tag collection is accessed as image.tags

However, what if you want to use a completely different name? I needed to do this recently and struggled to find any help in the DM documentation. As it turns out, it’s very simple. There’s an (AFAIK undocumented) option when defining associations where you can specify the class name of the target model for the relationship. Let’s say you have Person and Book objects and you want a one-to-many relationship between people and books called reading, you simply include the model option.


class Person
include DataMapper::Resource
has n, :reading, :model => 'Book'
end

Simple :-)


Shortlink

Logger version 4

I’ve updated my Flexible Logger to version 4. Changes for this version are:

* split plugins into individual files
* change error() to addError() to allow for a $logger->error(‘message’) method
* rename underscored properties
* better conformation to PSR standards
* more inline documentation

As usual you can clone the source from my GitHub repo


Shortlink

AutoLoader version 3

I’ve updated my PHP Auto Loader to version 3. Changes are as follows:

* A new index system
* Improved checking of missing classes
* Improved debugging
* A smarter caching system
* Better locking mechanism

In order to better comply with the PSR standards I’ve been refactoring some of my code. As a result the class name is now \opensourceame\AutoLoader though since PHP does not use case sensitivity for class names this won’t break any instantiations of the class. However, the file name to include is now called AutoLoader.php so require / include statements will have to be updated. As always you can get the latest version on my GitHub repository .


Shortlink

Phishers getting a free pass

Yesterday I received a phishing email with an HTML attachment. The HTML contained a form containing banking details which would be POSTed to a particular URL. (eg: http://somedodgysite.com/carddetails.php) After filling in the form with junk and posting it, I noticed that the response redirected my browser to a genuine banking page.

I reported the site to several phishing alert sites and was quite surprised to receive a few responses that basically said “URL not accepted – this URL redirects to a non-phishing site”.

What?

That logic makes it impossible to block dodgy target URLs. A phisher merely needs to redirect to a genuine banking URL to have their page whitelisted. There are two simple things that can be done to avoid this:

  • Security sites should allow a reporter to include further information when reporting the URL. Some do but even the mighty Google give you just a small text box to add a few lines of info to your report

  • Security sites should not automatically assume a URL is safe if it redirects to a genuine site. If several reports are made about the same URL then it should be considered bad with an option for the URL owner to appeal – much like an SMTP RBL

Are there other ways this “malicious URL” reporting could be improved?


Shortlink

Doctrine 1 alternative

I’m working with a lot of projects that use Doctrine1. The ORM is ageing somewhat and has been criticised for its performance overhead. At my current job I have written a REST API that provides an easy means of interacting with Doctrine models, much like Ruby on Rails does. It works very well and performs beyond our current (and short to mid-term needs) but will hit a bottleneck with tens of thousands of requests per hour.

I’m looking for a faster ActiveRecord style ORM for PHP. So far I’ve investigated a number of alternatives, like phpActiveRecord, but all of the projects I’ve looked at are inactive and barely maintained. (Note to project developers, it’s not a good sign when your help forum is riddled with spam!)

Do you have a recommendations? Porting to Doctrine2 looks like a nightmare, especially the lack of public access to properties that persist to the DB, but given the lack of alternatives it may be the only way forward …


Shortlink

JEditable – custom field name

I love JEditable, it’s an extremely useful way of having editable content on a page. I did come up against a limitation though. The name of the field is determined by the ID attribute of the containing DIV (or other element). Consider the following where you want fields to be editable for two different companies on the same page:

<div class="company" id="1">
 <div id="companyName1" class="editable" editField="name">First Company</div>
 <div id="companyCity1" class="editable" editField="city">First Company Location</div>
</div>

<div class="company" id="2">
 <div id="companyName2" class="editable" editField="name">Second Company</div>
 <div id="companyCity2" class="editable" editField="city">Second Company Location</div>
</div>

In order to make this work in JEditable you need to patch it and add an option to specify which attribute is used to determine the name of the field:

In version 1.7.1 modify line 326 as follows:


submitdata[settings.id] = $(self).attr(settings.fieldName);

and add below line 129 to set the default to “id” (as per normal JEditable behaviour):

fieldName : 'id',

That’s it! You can now do something like this to make each field editable:


$('.company .editable').each(function(n. el) {
$(el).editable('/company/save/' + el.id, { fieldName: "editField" });

Download the patched version here


Shortlink

Code on GitHub

I have started putting my public code onto GitHub. To get the latest copies of code, please use this link:

https://github.com/opensourceame

I will be documenting the process manager classes soon.


Shortlink

Stash classes online

I’ve made my Stash classes (a lightweight ORM / DBAL of sorts) available for download. The simplest way to explain how they work is through some example code:

 
/*
 * first install the database using the example.sql file that comes with this package
 */
 
define('DSN_STASH_TEST', 'mysql://test:test@localhost/stash_test');
 
require_once 'opensourceame.stash.php';
 
/*
 * This is the singular class for person objects
 */
class person extends stash_bean
{
	protected	$_stash_dsn 		= DSN_STASH_TEST;
	protected	$_stash_table		= 'people';
	protected	$_stash_fields		= array('id', 'first_name', 'last_name');
 
	public function name()
	{
		return $this->last_name.', '.$this->first_name;
	}
}
 
/*
 * This defines the class people as a collection of persons
 */
class people extends stash_collection
{
	protected	$_object_class		= 'person';	
}
 
/*
 * EXAMPLE: fetch an existing person and display the name
 */
 
$person = new person;
$person->retrieve('20fee9bd-5f4d-d34b-5605-4cefaaca32ab');
 
echo $person->name()."\n";
 
/*
 * EXAMPLE: save an archive of the existing record
 * then change the first name from "Will" to "William" and update the record
 */
 
$person->archive();
 
$person->first_name	= 'William';
$person->update();
 
 
/*
 * EXAMPLE: fetching multiple person objects as a collection
 */
$people = new people;
$people->add_condition("and last_name='Smith'");
$people->add_condition("or first_name='Helen'");
$people->retrieve();
 
foreach($people->collection() as $person)
{
	echo $person->name()."\n";
}