RSS
 

Archive for July, 2011

Bitcoins and CakePHP

20 Jul

When I started to try this out with a friend I was surprised how few resources there are. Especially in the CakePHP sector. Bitcoins are not very common yet – although quite promising: anonymous, not refundable payments without any transaction fees. A good info website is weusecoins.com, by the way.

Setup

You can run your own bitcoin daemon and use RPC to communicate with it. Setting up the bitcoind damon on a lenny was quite a mess. But with a more modern Debian squeeze it should be not that difficult. Using binaries will not work in all cases. So it might be necessary to compile it. Anyway – for a debian sqeeze (6) for example it is as easy as described here!

If it is set up and running you will have to create a user “bitcoind” which then has a wallet in his home directory. Test it with “su bitcoind” to switch to this user and type bitcoind getinfo. You should now see the current bitcoin settings as well as your total amount and other infos.

It is supposed to work with windows systems, as well. I didn’t try that, though.

The following article describes how to work with a shop system and bitcoins as payment. It requires a running bitcoin daemon.

I use github.com/mikegogulski/bitcoin-php as a vendor file as it provides basic access to the daemon.

Download and follow the instructions: github.com/dereuromark/CakePHP-Payment-Plugin

Settings

# in your configs.php
$config['Bitcoin'] = array(
    'account' => 'myaccountname',
);
 
# in your private config (which should not be part of the svn/git commit)
Configure::write('Bitcoin.username','myusername');
Configure::write('Bitcoin.password','mydaemonpassword');

The account name must match the account set as default in your daemon. Username and password are set in the /home/bitcoind/.bitcoind/bitcoin.conf:

...
 # You must set rpcuser and rpcpassword to secure the JSON-RPC api
rpcuser=...
rpcpassword=...

First tryouts

You can import the lib at any point and query it:

App::import('Lib', 'Payment.BitcoinLib');
$this->Bitcoin = new BitcoinLib();
$balance = $this->Bitcoin->getBalance(); # should be a numeric value if everything works

Check the test case for other methods and how to use them.

Checking received money

Probably the most important part:

$amount = $this->Bitcoin->getReceivedByAddress($address, 3);

It will tell you how much money you received. Since you always use a different address for a specific transaction you will know exactly who paid it and what for. The second param is the amount of confirmations. Set it to 3-6 just to be sure.

List all your transactions

$transactions = $this->Bitcoin->listTransactions();

You can then iterate over them and process the transactions manually.

Using the non-daemon (webservice) version

Might not be as safe and reliable – but it works. If you don’t set username or password it will automatically use the webservice if possible.

$amount = $this->Bitcoin->getReceivedByAddress('1PJ3Jy1T36BzxuikZDXY5YV7YjTmfcvQNc');

Note: Currently it always uses the webservice here as the daemon seems to return 0 in all cases.

Notes

The callback part of the model is not ready yet. Working on it. The basic idea: Running a cronjob every 5-10 minutes checking the pending transactions. It will then trigger the callback if new payments arrive. In the callback you can then decide what to do after the payment is received (and has the correct amount).

 
2 Comments

Posted in CakePHP

 

Introducing two CakePHP behaviors

05 Jul

Today I want to introduce two new CakePHP behaviors.

Jsonable Behavior

This is not so new, of course. Already existed as a basic version in the Bakery. I enhanced it to work with more than just plain arrays and added some more functionality.

The behavior can be found in the Tools Plugin.

In my first scenario where I used it, I had a geocoder behavior attached to the model which returned an array. I wanted to save all the returned values, though, for debugging purposes in a field “debug”. By using the following snippet I was able to do exactly that.

public $actsAs = array('Tools.Jsonable' => array('fields' => array('debug'), 'map' => array('geocoder_result'));

I could access the array in the view as any other array since the behavior re-translates it back into an array on find(). Note: the mapping option is useful if you want to rename certain fields. In my case the geocoder puts its data into $this->data[‘Model’][‘geocoder_result’]. I might need to access this array later on in the model. So I “jsonable” it in the “debug” field for DB input and leave the source field untouched.

That’s all very nice. But what if needed something more frontend suitable. I want to be able to use a textarea field where I can put all kinds of params which will then also be available as array afterwards (as long as you are not in edit mode, of course).

In our add/edit actions we need to switch to param style:

$this->Model->Behaviors->unload('Jsonable');
$this->Model->Behaviors->load('Tools.Jsonable', array('fields' => 'details', 'input' => 'param', 'output' => 'param'));

The form contains a “details” textarea field. We can insert:

param1:value1|param2:value2

In our views we get our data now as array:

array('Model' => array(..., 'details' => array('param1' => 'value1', 'param2' => 'value2')));

And, of course, as third use case we can also simulate an ENUM by using:

$this->Model->Behaviors->unload('Jsonable');
$this->Model->Behaviors->load('Tools.Jsonable', array('fields' => 'tags', 'sort' => true, 'input' => 'list', 'output' => 'list'));

Note: The default value in the model itself still needs to be array in order to transform them into a list on find()! That’s why we only override them in the form views.

In our textarea we can now type:

dog, cat, cat, fish

In our views we would result in (var $data[‘Model’][‘tags’])

array('cat', 'dog', 'fish');

Note the cleanup automation you can additionally turn on/off. There are more things to explore. But I will stop here for now.

Yes – you could make a new table/relation for this in the first place. But sometimes it’s just quicker to create such an enumeration field. Bear in mind: It then cannot be sorted/searched by those values, though. For a more static solution take a look at my Static Enums.

Confirmable Behavior

This I invented a while ago working on a registration page. After I needed the same functionatily on other sites, as well, I started to build a behavior out of it. Now I don’t have to repeat myself anymore. On Github you can find the Confirmable behavior.

Example Usage in an action:

// if posted
$this->Model->Behaviors->load('Tools.Confirmable', array('field' => 'confirmation', 'message' => 'My custom message'));
$this->Model->set($this->data);
if ($this->Model->validates()) {
    // OK
}

In the corresponding view of this action:

echo $this->Form->input('confirmation', array('type' => 'checkbox', 'label' => __('Yes, I actually read it')));

The user has to check the toggle field provided. Otherwise validation will fail.

Some notes on behavior development

Make sure you return the right boolean value in those beforeValidate() methods etc. Usually this should be TRUE even if it fails. The reason is you want to display all errors at once in the form. If you return FALSE too soon, the other validation methods won’t get triggered and you have a staged validation which is a bad thing. So return TRUE. And don’t worry, as long as there are errors the save method won’t get triggered.

As you can see the settings are always “per Model->alias”. This way multiple models with the same behavior won’t interfere which each other (since they all use the behavior instance – yes, that’s the CakePHP way of saving resources, I guess).

Update 2013-08

I upgraded the examples from 1.x to 2.x code.

2014-01-22

Modified the methods to 2.4/2.5 syntax: attach=>load and detach=>unload

 
2 Comments

Posted in CakePHP