/viz-php-lib

Native PHP class for VIZ Keys, Transaction, JsonRPC

Primary LanguagePHPMIT LicenseMIT

viz-php-lib

VIZ PHP Library

Native PHP class for VIZ Keys, Transaction, JsonRPC

Features

  • JsonRPC — native socket usage (all API methods, hostname cache, ssl flag, full result flag)
  • Keys — private (sign), public (verify), shared, encoded keys support (wif, public encoded, compressed/uncompressed public key in hex representation)
  • Transaction — easy workflow, multi-signature support, multi-operations support, execute by JsonRPC, support all 38 operations: transfer, transfer_to_vesting, withdraw_vesting, award, create_invite, etc...
  • Classes support PSR-4
  • Contains modificated classes for best fit to VIZ Blockchain (all-in-one)
  • Native code without additional installations (sry composer, but we need other changes in third-party classes)
  • Utils for keys compatibility with Ethereum, Bitcoin addresses
  • Utilities with (Voice protocol)[https://github.com/VIZ-Blockchain/Free-Speech-Project/blob/master/specification.md] support: voice_text, voice_publication
  • MIT License

Dependencies

One PHP extension from the list:

  • GMP (GNU Multiple Precision) — sudo apt-get install libgmp-dev php-gmp
  • BCMath — sudo apt-get install php-bcmath

Most hosting providers have it turned on already, but if not found, check your control panel.

Thanks to third-party class developers:

Examples

Some examples have placeholders for private keys or accounts. Change them for successfull test.

Keys: init from hex, encode to wif, get public key from private, get encoded version, verify signature.

<?php
include('./class/autoloader.php');

$private_key=new VIZ\Key('b9f3c242e5872ac828cf2ef411f4c7b2a710bd9643544d735cc115ee939b3aae');
print 'Private key from hex: '.$private_key->hex.PHP_EOL;
print 'Private key WIF: '.$private_key->encode().PHP_EOL;
$data='Hello VIZ.World! '.date('d.m.Y H:i:s');
print 'Data for signing: '.$data.PHP_EOL;
$signature=$private_key->sign($data);
if(false===$signature){
	print 'Canonical signature was not found, please try again.';
}
else{
	print 'Signature: '.$signature.PHP_EOL;
	$public_key=$private_key->get_public_key();
	$recovered_public_key=$public_key->recover_public_key($data,$signature);
	print 'Recovered public key from signature: '.$public_key->encode().PHP_EOL;

	if($public_key){
		print 'Public key from private: '.$public_key->encode().PHP_EOL;
		print 'Verify signature status for same data: '.var_export($public_key->verify($data,$signature),true).PHP_EOL;
		print 'Verify signature status for other data: '.var_export($public_key->verify('Bye VIZ.World!',$signature),true).PHP_EOL;
	}
}

JsonRPC: init with endpoint, api method without parameters, change endpoint, get account, turn on all json result, request a non-existent account.

<?php
include('./class/autoloader.php');

$api=new VIZ\JsonRPC('https://node.viz.plus/');
$dgp=$api->execute_method('get_dynamic_global_properties');
var_dump($dgp);

$api->endpoint='https://node.viz.media/';

$account_login='on1x';
$account=$api->execute_method('get_account',[$account_login,'']);
if(false!==$account){
	print PHP_EOL.'Account '.$account_login.' was founded:';
	var_dump($account);
}

$api->return_only_result=false;

$account_login='strange.viz';
$account=$api->execute_method('get_account',[$account_login,'']);
if(isset($account['error'])){
	print PHP_EOL.$account['error']['message'];
}

Transaction: init with endpoint and private key in wif, build simple transaction with award operation and execute it.

<?php
include('./class/autoloader.php');
$initiator='account';
$initiator_private_key='5Jaw8HtYbPDWRDhoH3eojmwquvsNZ8Z9HTWCsXJ2nAMrSxNPZ4F';

$tx=new VIZ\Transaction('https://node.viz.plus/',$initiator_private_key);
$tx_data=$tx->award($initiator,'committee',1000,0,'testing viz-php-lib award operation');
var_dump($tx_data);

$tx_status=$tx->execute($tx_data['json']);
var_dump($tx_status);

Init with endpoint and private key in wif, activate queue mode and add 2 operations, end queue and get result array. Execute transaction json from array. Add additional signature for multi-sig example (can be false if canonical signature was not found).

<?php
include('./class/autoloader.php');
$initiator='some.account';
$initiator_private_key='5Jaw8HtYbPDWRDhoH3eojmwquvsNZ8Z9HTWCsXJ2nAMrSxNPZ4F';

$tx=new VIZ\Transaction('https://node.viz.plus/',$initiator_private_key);
$tx->start_queue();
$tx->award($initiator,'committee',1000,0,'testing viz-php-lib multi-operations');
$tx->award($initiator,'committee',2000,0,'testing viz-php-lib multi-operations 2');
$tx_data=$tx->end_queue();
var_dump($tx_data);

//turn api flag to return all result (including error state)
$tx->api->return_only_result=false;
$tx_status=$tx->execute($tx_data['json']);
var_dump($tx_status);

$tx2_data=$tx->add_signature($tx_data['json'],$tx_data['data'],'5HrmLC83FybxVgJ5jXQN5dUHxXZfHVc27sYpjdnoTviRqppPhPN');
var_dump($tx2_data);

Create new private key, get public key from it, execute transaction with create_invite operation.

<?php
include('./class/autoloader.php');

$key=new VIZ\Key();
$key_data=$key->gen('some seed, salt will be input','there');
print 'Key seed with inputed salt: '.$key_data[0].PHP_EOL;

$key_data=$key->gen('some seed, salt will be generated');
print 'Key seed with random salt: '.$key_data[0].PHP_EOL;

print 'Private key (wif): '.$key_data[1].PHP_EOL;
print 'Private key (wif) from object: '.$key->encode().PHP_EOL;
print 'Public key (encoded): '.$key_data[2].PHP_EOL;
print 'Public key (encoded) from object: '.$key_data[3]->encode().PHP_EOL;

$tx=new VIZ\Transaction('https://node.viz.plus/','5JWm...');

$tx_data=$tx->create_invite('on1x','50.005 VIZ',$key_data[2]);
var_dump($tx_data);

$tx_status=$tx->execute($tx_data['json']);
var_dump($tx_status);

Find shared key from two sides. Simple string encrypt and decrypt with AES-256-CBC. Encode and decode memo with viz-js-lib compability structure for encrypted memo.

<?php
include('./class/autoloader.php');

$private_key1=new VIZ\Key();
$private_key1->gen();
$public_key1=$private_key1->get_public_key();
print '$public_key1: '.$public_key1->encode().PHP_EOL;

$private_key2=new VIZ\Key();
$private_key2->gen();
$public_key2=$private_key2->get_public_key();
print '$public_key2: '.$public_key2->encode().PHP_EOL;

$shared_key1=$private_key1->get_shared_key($public_key2->encode());
print '$shared_key1: '.$shared_key1.PHP_EOL;

$shared_key2=$private_key2->get_shared_key($public_key1->encode());
print '$shared_key2: '.$shared_key2.PHP_EOL;

$string='Hello VIZ World! 🤘';

$encrypted=VIZ\Utils::aes_256_cbc_encrypt($string,hex2bin($shared_key1));
$decrypted=VIZ\Utils::aes_256_cbc_decrypt(hex2bin($encrypted['data']),hex2bin($shared_key2),hex2bin($encrypted['iv']));

print PHP_EOL.'Simple encrypted AES-256-cbc with $shared_key1: '.var_export($encrypted,true).PHP_EOL;
print PHP_EOL.'Simple decrypted AES-256-cbc with $shared_key2: '.var_export($decrypted,true).PHP_EOL;

$crypted=$private_key1->encode_memo($public_key2->encode(),$string);
print PHP_EOL.'Crypted memo by AES-256-cbc with shared key between private_key1 and public_key2: '.var_export($crypted,true).PHP_EOL;

$result=$private_key2->decode_memo($crypted);
print PHP_EOL.'Decrypted memo by AES-256-cbc with shared key between private_key2 and public_key1: '.var_export($result,true).PHP_EOL;

$result=$private_key1->decode_memo($crypted);
print PHP_EOL.'Decrypted memo by AES-256-cbc with shared key between private_key1 and public_key2: '.var_export($result,true).PHP_EOL;

$result=$private_key3->decode_memo($crypted);
print PHP_EOL.'Decrypted memo by AES-256-cbc with shared key between private_key3 and public_key1: '.var_export($result,true).PHP_EOL;

Generate data and signature for passwordless authentication and check it for domain auth action with active authority.

<?php
include('./class/autoloader.php');
$account='invite';
$private_key=new VIZ\Key('5KcfoRuDfkhrLCxVcE9x51J6KN9aM9fpb78tLrvvFckxVV6FyFW');
print 'Private key WIF: '.$private_key->encode().PHP_EOL;
list($data,$signature)=$private_key->auth($account,'domain.com','auth','active');
print 'Data for auth: '.$data.PHP_EOL;
print 'Signature: '.$signature.PHP_EOL;

$viz_auth=new VIZ\Auth('https://node.viz.plus/','domain.com','auth','active');
$auth_status=$viz_auth->check($data,$signature);
print 'Passwordless authentication: '.var_export($auth_status,true);

Make transaction with custom operation.

<?php
include('./class/autoloader.php');
$account='test';
$private_key='5K...';//regular
$tx=new VIZ\Transaction('https://node.viz.plus/',$private_key);
$tx_data=$tx->custom([],[$account],'test','{"msg":"testing viz-php-lib custom operation"}');
var_dump($tx_data);

$tx->api->return_only_result=false;
//second attribute is synchronous, if setted then return block num where transaction was witnessed
$tx_status=$tx->execute($tx_data['json'],true);
var_dump($tx_status);

Make transaction with account create operation.

<?php
include('./class/autoloader.php');
$account='test';
$private_key='5K...';//regular
$tx=new VIZ\Transaction('https://api.viz.world/',$private_key);

$fee='0.000 VIZ';
$delegation='10.000000 SHARES';

//you can set any authority as simple string with encoded public key
$master='VIZ7RXhpaw8SbedSp84EqMGGzeBZgAPLEn7D6kQhJu8bMMvUKtuxk';//5JRd4Toy8cmDr15qEtZieqAgbg3qQMU6n8cPC1Las2hBah46tr1
$active='VIZ7H8S8rHkKQkX8bSUpDtBAwy8tTphq2NH7ZRv1dcCvk1Cjz38nK';//5JvgdGsA5M8rZ9oY2p7qcKkexG1kWqN2jQcQ6afEPCqQXrKTsbS

//or make full authority struct (if you need more flexibility)
$regular=[
	//'weight_threshold'=>1,//can be empty if weight_threshold=1
	'account_auths'=>[
		['on1x',1]
	],
	'key_auths'=>[
		['VIZ5bGNeJPjoDdZTEK3LSMUfP21gcBH34AdMPHpvQymuYMk2YMbsB',1],//5HuHKQhiiAAAp7zMCgRpCCyv8hramEmzAzDUagrhMkTWDhyVtK6
		['VIZ5jWA94PYBanGSPhTyWrwvT8RAJcnB7onXGvK5DnzbxB6874yap',1]//5KESchwZvs67C4Xz5SQQ1ea4N9rZR67NEvi6yemWpSYoKo9eTrM
	]
];
//you need manually check public keys sorting in key_auths or node will refuse the transaction

$memo_key='VIZ1111111111111111111111111111111114T1Anm';//can be empty key

$json_metadata='';
$referrer='';

$new_account_name='test-lib';

$tx_data=$tx->account_create($fee,$delegation,$account,$new_account_name,$master,$actove,$regular,$memo_key,$json_metadata,$referrer);
var_dump($tx_data);

$tx->api->return_only_result=false;
$tx_status=$tx->execute($tx_data['json']);
var_dump($tx_status);

Make transaction with proposal operations as array (need to use build_ prefix). Approve that proposal with other account active key.

<?php
include('./class/autoloader.php');
$account='test';
$private_key='5K...';//regular
$account2='test2';
$private_key2='5K...';//active

$tx=new VIZ\Transaction('https://api.viz.world/',$private_key);
$tx_data=$tx->proposal_create($account,'test','test proposal operation builder','2021-03-03T12:00:01',[$tx->build_transfer($account2,'committee','1.000 VIZ','proposed operation 1'),$tx->build_transfer($account2,'committee','2.000 VIZ','proposed operation 2')],false);
var_dump($tx_data);

$tx_status=$tx->execute($tx_data['json']);
var_dump($tx_status);

$tx2=new VIZ\Transaction('https://api.viz.world/',$private_key2);
$tx2_data=$tx2->proposal_update($account,'test',[$account2]);
var_dump($tx2_data);

$tx2_status=$tx->execute($tx2_data['json']);
var_dump($tx2_status);

Utils method for post text object to Voice protocol. Method attributes (* - is optional):

Attribute Description
text Simple text note.
reply* Link to replied context in viz:// url scheme.
share* Link to shared context in any url scheme.
beneficiaries* Array of objects [] contains ["account"=>"committee","weight"=>100] for awarding beneficiaries details.
loop* Block num. Ability to make loop for previous objects, exclude from personal activity feed.
<?php
include('./class/autoloader.php');
$account='test';
$private_key='5K...';//regular
//$endpoint,$key,$account,$text,$reply=false,$share=false,$beneficiaries=false,$loop=false
$status=VIZ\Utils::voice_text('https://api.viz.world/',$private_key,$account,'Test from viz-php-lib');
var_dump($status);

Utils method for post publication object to Voice protocol. Method attributes (* - is optional):

Attribute Description
title Publication title.
markdown Publication text with voice markdown.
description* Publication short description for preview.
image* Link to publication image for preview thumbnail.
reply* Link to replied context in viz:// url scheme.
share* Link to shared context in any url scheme.
beneficiaries* Array of objects [] contains ["account"=>"committee","weight"=>100] for awarding beneficiaries details.
loop* Block num. Ability to make loop for previous objects, exclude from personal activity feed.
<?php
include('./class/autoloader.php');
$account='test';
$private_key='5K...';//regular
$markdown='Well, Voice protocol markdown have **bold**, __italic__, ~~stroke~~ and `code`

## Headers 2

### And 3

Also we got:

> Quotes and

>> Second style for citation

Support lists:

* Unordered
* as ordinary
* items

And ordered, ofc:

*n Yes
*n it is!

After all, simple images:
![Alt text for image](https://viz.world/ubi-circle-300.jpg)

Paragraph
with
multiline

...and #en #example tags support :)';
//$endpoint,$key,$account,$title,$markdown,$description,$image,$reply=false,$share=false,$beneficiaries=false,$loop=false,$synchronous=false
$status=VIZ\Utils::voice_publication('https://api.viz.world/',$private_key,$account,'Test publication from viz-php-lib',$markdown);
var_dump($status);

Create Voice text object, hide it with Voice Event.

<?php
include('./class/autoloader.php');
$account='test';
$private_key='5K...';
$text='Test text and event from viz-php-lib';

//create Voice object with text type (last attribute is synchronous that returns block num where is transaction was witnessed)
$object_block_num=VIZ\Utils::voice_text('https://api.viz.world/',$private_key,$account,$text,false,false,false,false,true);
print 'Object: viz://@'.$account.'/'.$object_block_num.'/';

//hide event
$event_block_num=VIZ\Utils::voice_event('https://api.viz.world/',$private_key,$account,'h',false,$object_block_num,false,false,true);
print 'Hide event for this object: viz://@'.$account.'/'.$object_block_num.'/?event='.$event_block_num;

Create Voice text object, check transaction size, split it for add Voice Event.

<?php
include('./class/autoloader.php');
$account='test';
$private_key='5K...';
$max_size_limit=65280;
$part_size=1024*10;//10Kb

$long_text='...';//long text more that $max_size_limit bytes

//create Voice object with text type (last attribute is synchronous that returns block num where is transaction was witnessed)
$tx_prepare=VIZ\Utils::voice_text('https://api.viz.world/',$private_key,$account,$long_text,false/*reply*/,false/*share*/,false/*beneficiaries*/,false/*loop*/,true/*synchronous*/,true/*raw tx*/);
$tx_length=strlen($tx_prepare['data'])/2;
if($tx_length<$max_size_limit){
	$object_block_num=VIZ\Utils::voice_text('https://api.viz.world/',$private_key,$account,$long_text,false/*reply*/,false/*share*/,false/*beneficiaries*/,false/*loop*/,true/*synchronous*/,false/*raw tx*/);
	if($object_block_num){
		print 'Object: viz://@'.$account.'/'.$object_block_num.'/';
	}
	else{
		print 'Object error';
	}
}
else{
	$tx_diff=$tx_length-$max_size_limit;
	$parts_count=ceil($tx_diff / $part_size);

	$markdown_length=mb_strlen($long_text);
	$main_part_length=$markdown_length-($parts_count*$part_size);
	if($main_part_length<0){
		$main_part_length=$part_size;
	}
	$main_part=mb_substr($long_text,0,$main_part_length);
	$secondary_part=mb_substr($long_text,$main_part_length);
	$object_block_num=VIZ\Utils::voice_text('https://api.viz.world/',$private_key,$account,$main_part,false/*reply*/,false/*share*/,false/*beneficiaries*/,false/*loop*/,true/*synchronous*/,false/*raw tx*/);
	if($object_block_num){
		print 'Main object: viz://@'.$account.'/'.$object_block_num.'/'.PHP_EOL;
		//add event
		$event_block_num=VIZ\Utils::voice_event('https://api.viz.world/',$private_key,$account,'a',false,$object_block_num,false/*data_type*/,['t'=>$secondary_part]/*data*/,true/*synchronous*/,false/*raw tx*/);
		if($event_block_num){
			print 'Add event for this object: viz://@'.$account.'/'.$object_block_num.'/?event='.$event_block_num;
		}
		else{
			print 'Event error';
		}
	}
	else{
		print 'Object error';
	}
}

May VIZ be with you.