PHP Classes

File: blockchain.php

Recommend this page to a friend!
  Classes of Rodrigo Faustino   Blockchain PHP Script   blockchain.php   Download  
File: blockchain.php
Role: Auxiliary script
Content type: text/plain
Description: Auxiliary script
Class: Blockchain PHP Script
Examples to show how to manipulate a blockchain
Author: By
Last change:
Date: 10 months ago
Size: 2,824 bytes
 

Contents

Class file image Download
<?php
/**
 * A very simple BlockChain implementation intended to illustrate the concept.
 *
 * Marty Anstey (https://marty.anstey.ca/)
 * August 2015
 *
 * The block index simply maps a block to a disk offset for convenience.
 * It's not necessary, but it makes it much easier to quickly locate any
 * block within the chain.
 *
 * ISAM index:
 * [4] count
 * -----------
 * [4] offset
 * [4] length
 * ...
 *
 * Block format:
 * [4] magic
 * [1] format (0x01)
 * [4] timestamp
 * [n] hash of previous block
 * [4] data length
 * [?] data
 *
 *
 */
define('_magic', 0xD5E8A97F);
define('_hashalg', 'sha256');
define('_hashlen', 32);
define('_blksize', (13 + _hashlen));

/*
$res = addblock('blockchain.dat','Some data');
if ($res!==TRUE) exit("ERROR: ".$res."\n");
*/

function addblock($fn,$data,$genesis=FALSE) {
   
$indexfn = $fn.'.idx';
    if (!
$genesis) {
        if (!
file_exists($fn)) return('Missing blockchain data file!');
        if (!
file_exists($indexfn)) return('Missing blockchain index file!');
       
// get disk location of last block from index
       
if (!$ix = fopen($indexfn, 'r+b')) return("Can't open ".$indexfn);
       
$maxblock = unpack('V', fread($ix,4))[1];
       
$zpos = (($maxblock*8)-4);
       
fseek($ix, $zpos, SEEK_SET);
       
$ofs = unpack('V', fread($ix, 4))[1];
       
$len = unpack('V', fread($ix, 4))[1];
       
// read last block and calculate hash
       
if (!$bc = fopen($fn,'r+b')) return("Can't open ".$fn);
       
fseek($bc, $ofs, SEEK_SET);
       
$block = fread($bc, $len);
       
$hash = hash(_hashalg, $block);
       
// add new block to the end of the chain
       
fseek($bc, 0, SEEK_END);
       
$pos = ftell($bc);
       
write_block($bc, $data, $hash);
       
fclose($bc);
       
// update index
       
update_index($ix, $pos, strlen($data), ($maxblock+1));
       
fclose($ix);
        return
TRUE;
    }
    else
    {
        if (
file_exists($fn)) return('Blockchain data file already exists!');
        if (
file_exists($indexfn)) return('Blockchain index file already exists!');
       
$bc = fopen($fn, 'wb');
       
$ix = fopen($indexfn, 'wb');
       
write_block($bc, $data, str_repeat('00', _hashlen));
       
update_index($ix, 0, strlen($data), 1);
       
fclose($bc);
       
fclose($ix);
        return
TRUE;
    }
}

function
write_block(&$fp, $data, $prevhash) {
   
fwrite($fp, pack('V', _magic), 4); // Magic
   
fwrite($fp, chr(1), 1); // Version
   
fwrite($fp, pack('V', time()), 4); // Timestamp
   
fwrite($fp, hex2bin($prevhash), _hashlen); // Previous Hash
   
fwrite($fp, pack('V', strlen($data)), 4); // Data Length
   
fwrite($fp, $data, strlen($data)); // Data
}

function
update_index(&$fp, $pos, $datalen, $count) {
   
fseek($fp, 0, SEEK_SET);
   
fwrite($fp, pack('V', $count), 4); // Record count
   
fseek($fp, 0, SEEK_END);
   
fwrite($fp, pack('V', $pos), 4); // Offset
   
fwrite($fp, pack('V', ($datalen+_blksize)), 4); // Length
}