Difference between revisions of "PHP developer intro"

From Bitcoin Wiki
Jump to: navigation, search
(Setting up Bitcoin)
(Removed out-of-date getinfo method and replaced with getblockchaininfo)
 
(34 intermediate revisions by 21 users not shown)
Line 1: Line 1:
 
'''L'''inux '''A'''pache '''M'''ySQL '''P'''HP + Bitcoin tutorial.
 
'''L'''inux '''A'''pache '''M'''ySQL '''P'''HP + Bitcoin tutorial.
  
For the sake of this tutorial we assume an Ubuntu server running with PHP. The use case here is integrating a shopping system to accept Bitcoins. We assume some knowledge of Bitcoin and experience in PHP.
+
For this introduction we assume that you have GNU/Linux server with Apache and PHP and that you wish to interact with the Bitcoin network from a web application. We assume some knowledge of Bitcoin and experience in PHP.
  
You can substitute any other language here for PHP. See the associated [[API reference (JSON-RPC)|API reference]] pages for info on other languages.
+
While this is written for PHP, the same principles apply for other languages. See the associated [[API reference (JSON-RPC)|API reference]] pages for info on other languages.
  
You will run Bitcoin in daemon mode. The way PHP communicates is through localhost HTTP requests. You use a library called [http://jsonrpcphp.org/ JSON-RPC] to call the various functions. It will respond back with a [http://en.wikipedia.org/wiki/Json JSON object].
+
The easiest way to get started is to run Bitcoin in daemon mode with which PHP communicates via local HTTP requests. A library called [http://jsonrpcphp.org/ JSON-RPC] is used to call the various functions of bitcoind, which will respond back with a [http://en.wikipedia.org/wiki/Json JSON object].
 +
 
 +
It is however recommended to use one of the [[#Alternative_Libs_For_RPC|Alternative Libraries]] listed below instead, since they are more sophisticated.
  
 
== Setting up Bitcoin ==
 
== Setting up Bitcoin ==
  
Bitcoins are stored internally as 64 bit integers. Because PHP's JSON implementation does not provide a way to use custom types for decimal numbers, we must use an alternative branch of Bitcoin which returns all decimal amounts as strings.
+
You can download the Bitcoin daemon from the [[Main_Page|homepage]] and run one of the included binaries or compile your own from the included source code. See [[Running Bitcoin]] for details on configuring bitcoind.
 
 
<source lang="bash">
 
# install needed packages
 
$ sudo apt-get install build-essential libboost-all-dev libdb4.7++-dev libssl-dev libglib2.0-dev
 
$ git clone git://github.com/genjix/bitcoin.git
 
$ cd bitcoin/
 
$ make -f makefile.unix bitcoind
 
</source>
 
  
Before running bitcoind you will need to create a file in ~/.bitcoin/bitcoin.conf
+
Before running bitcoind you will need to create a configuration file in the Bitcoin data directory (~/.bitcoin/bitcoin.conf on Linux):
 
<source lang="bash">
 
<source lang="bash">
 
rpcuser=user
 
rpcuser=user
rpcpassword=password
+
rpcpassword={you MUST pick a unique password to be secure}
 
</source>
 
</source>
 +
If you miss this step, bitcoind will remind you.
  
 
Now run bitcoind:
 
Now run bitcoind:
Line 29: Line 24:
 
$ ./bitcoind
 
$ ./bitcoind
 
# wait a few seconds for it to start up
 
# wait a few seconds for it to start up
$ ./bitcoind getinfo
+
$ ./bitcoin-cli getblockchaininfo
# various info shown
+
# various information will be shown. If you get an error, try again until you see some useful output.
$ ./bitcoind help
+
$ ./bitcoin-cli help
# help on commands
+
# get help on commands, note no dash before help
 
</source>
 
</source>
  
Bitcoin is now initialising and you must wait until "blocks" is at the [http://bitcoinwatch.com/ current count].
+
Bitcoin will begin synchronizing with the network and downloading a complete copy of the block chain. As of August 2012, more than 2gb of data must be downloaded and verified during this process. It may take two or more hours to complete. You will know when it's done when the block count reaches the [http://blockexplorer.com/q/getblockcount current count].
  
== First steps ==
+
== Getblockchaininfo (Bitcoind's version of Hello World) ==
  
Assuming Bitcoin has finished the initialisation process; download the file jsonRPCClient.php from [http://jsonrpcphp.org/ JSON-RPC PHP]. The other files can be safely discarded.
+
Assuming Bitcoin has finished the initialisation process; download the file jsonRPCClient.php from [http://jsonrpcphp.org/ JSON-RPC PHP] and place it in a web-accessible location.
 +
 
 +
Second, create a PHP file with the following and visit it with your browser to test.
  
 
<source lang="php">
 
<source lang="php">
Line 47: Line 44:
 
    
 
    
 
   echo "<pre>\n";
 
   echo "<pre>\n";
   print_r($bitcoin->getinfo());
+
   print_r($bitcoin->getblockchaininfo());
 
   echo "</pre>";
 
   echo "</pre>";
 
</source>
 
</source>
 +
 +
'''Note:''' The jsonRPCClient library uses fopen() and will throw an exception saying "Unable to connect" if it receives a 404 or 500 error from bitcoind. This prevents you from being able to see error messages generated by bitcoind (as they are sent with status 404 or 500). The [[#Alternative_Libs_For_RPC|Alternative Libraries]] listed below are similar in function to JSON-RPC PHP but do not have this issue.
  
 
== Precision ==
 
== Precision ==
  
Because PHP has no option to JSON decode to accurate decimal class, you should internally use GMP. Treat each number like a large int with 8 decimal places (this can be trimmed for display).
+
Bitcoin amounts can range from 1 Satoshi (0.00000001 BTC) to nearly 2,100,000,000,000,000 (21,000,000 BTC).  To avoid rounding errors, you must make sure your PHP implementation supports the full range of Bitcoin values without losing precision.  Most PHP implementations use IEEE 64-bit double-precision floating point numbers with 53 bits of precision, which is enough to correctly represent the full range of bitcoin values.
  
Our version of Bitcoin treats every monetary value as int64 8 decimal strings. So 1 BTC will be "100000000". Use PHP's GMP functions to manipulate these values accurately.
+
See [[Proper Money Handling (JSON-RPC)]] for more information.
  
For converting between internal GMP numbers and display/user input, you can use these functions:
+
If your PHP implementation does not support 64-bit numbers (again, this is very rare), you must use a version of bitcoind that sends values as strings (genjix maintains a fork at http://github.com/genjix/bitcoin) and use the  [http://php.net/manual/en/ref.gmp.php GMP] and [http://php.net/manual/en/ref.bc.php BC Math] libraries for all calculations involving bitcoin amounts.
<source lang="php">
+
 
# converts a user supplied number to our internal representation
+
== Accounts ==
#  3.14 => "314000000"
+
 
# accepts strings, floats and ints as input
+
In Bitcoin, money is sent to addresses and many addresses can be held by one wallet. The balance shown by default in bitcoind is the sum of the bitcoins in all the addresses in the wallet.
function numstr_to_internal($numstr)
+
 
{
+
Bitcoin goes another step. You can have [[Accounts explained|accounts]]. Each account holds multiple addresses and acts like a mini-bitcoind.  
    return bcmul($numstr, pow(10, 8), 0);
 
}
 
# converts an internal number to an end user number for display as defined by precision
 
#  314100000 => "3.14"
 
# accepts GMP numbers, ints and strings as input
 
function internal_to_numstr($num, $precision=2)
 
{
 
    $repr = gmp_strval($num);
 
    $repr = bcdiv($repr, pow(10, 8), $precision);
 
    # now tidy output...
 
    # trim trailing 0s
 
    $repr = rtrim($repr, '0');
 
    # and a trailing . if it exists
 
    $repr = rtrim($repr, '.');
 
    return $repr;
 
}
 
  
$num_internal = numstr_to_internal("3.141");
+
<source lang="bash">
echo "<p>".$num_internal."</p>";
+
$ ./bitcoin-cli listaccounts
$num_display = internal_to_numstr($num_internal);
+
# show list of accounts and various info for each one
echo "<p>".$num_display."</p>";
+
$ ./bitcoin-cli getaccountaddress user889
 +
# get an address to receive money to that is unique for the account user889
 +
$ ./bitcoin-cli getbalance user889
 +
# get the sum of all the money in the addresses owned by the account user889
 
</source>
 
</source>
  
If you need to do a decimal division in GMP, then GMP only supports integer division + a remainder ([http://php.net/manual/en/function.gmp-div-qr.php gmp_div_qr]). The work-around for this, is to use the bcmath module:
+
In your application, each user should have a unique username. You may then query bitcoind for a unique address using $bitcoin->getaccountaddress("user889"); [gets the first address for user889] or $bitcoin->getnewaddress("user889"); [creates a new address for user889].
 +
 
 +
The customer then deposits to this address.
 +
 
 +
You can check the funds for that customer by doing $bitcoin->getbalance("user889", 4);. The 4 indicates the minimum number of confirmations we will accept before assuming this payment is valid.
 +
 
 +
If you will be using accounts for multiple deposits and withdrawals long-term, you may want to consider tracking user balances in your own database. This simplifies transfers between your application's accounts and decouples your accounts from the Bitcoin wallet.
 +
 
 +
=== getnewaddress vs getaccountaddress ===
 +
 
 +
Using getnewaddress helps increase maintain anonymity of your users by making it hard for a malicious agent to track payments flowing through your application. Running getnewaddress too often, however, will cause your wallet to become filled with many empty addresses.
 +
 
 +
It is therefore recommended to in some way limit the number of unfunded addresses each user can request. Here is an example using sessions:
 
<source lang="php">
 
<source lang="php">
$a = gmp_init("100");
+
<?php
$b = gmp_init("3");
+
    require_once('jsonRPCClient.php');
echo "<p>".bcdiv(gmp_strval($a), gmp_strval($b), 3)."</p>";
+
    $bitcoin = new jsonRPCClient('http://root:root@127.0.0.1:8332/');  
 +
    # now check for appropriate funds in user account
 +
    try {
 +
        $username = ...
 +
        if(isset($_SESSION['sendaddress']))
 +
            $sendaddress = $_SESSION['sendaddress'];
 +
        else {
 +
            $sendaddress = $bitcoin->getnewaddress($username);
 +
            $_SESSION['sendaddress'] = $sendaddress;
 +
        }
 +
        $balance = $bitcoin->getbalance($username);
 +
    }
 +
    catch (Exception $e) {
 +
        die("<p>Server error! Please contact the admin.</p>");
 +
    }
 +
?>
 
</source>
 
</source>
  
Note that bcdiv only uses strings.
+
This creates a new address at the beginning of every new session, and stores it in the session variable.
 +
 
 +
==Alternative Libs For RPC==
 +
There are alternative PHP libraries for connecting to the bitcoind RPC which are recommended over using the plain jsonRPCClient.php class.
 +
They do not rely on magic __call, use cURL instead of fopen and have better error handling (and can be installed using composer).
 +
 
 +
* [https://github.com/nbobtc/bitcoind-php NboBTC Bitcoind-PHP]
 +
* [https://github.com/aceat64/EasyBitcoin-PHP EasyBitcoin-PHP]
 +
 
 +
==Alternative CLI clients==
 +
 
 +
* [https://github.com/dan-da/jsonrpc-cli jsonrpc-cli] provides simple jsonrpc queries from the command-line with highlighted json results (colors) and the ability to view/debug raw http requests and responses.  It can also display json results in php print_r, var_dump, serialize formats as well as yaml.
 +
 
 +
==See Also==
  
See also: [http://php.net/manual/en/ref.gmp.php GMP] and [http://php.net/manual/en/ref.bc.php BC Math] manuals.
+
* [[API reference (JSON-RPC)]]
 +
* [[Lazy_API]]
 +
* [https://github.com/cryptoapi/Payment-Gateway Bitcoin-PHP Payment library]
 +
* [[Merchant Howto]]
 +
* [[https://github.com/Bit-Wasp/bitcoin-lib-php Bitcoin-Lib-PHP - PHP Lib implementing signing of transactions, BIP32, etc]]
  
== Accounts ==
+
[[es:Introducción para desarrolladores de PHP]]
 +
[[de:Einführung_für_PHP-Entwickler]]
 +
 
 +
[[Category:Developer]]

Latest revision as of 21:12, 25 February 2020

Linux Apache MySQL PHP + Bitcoin tutorial.

For this introduction we assume that you have GNU/Linux server with Apache and PHP and that you wish to interact with the Bitcoin network from a web application. We assume some knowledge of Bitcoin and experience in PHP.

While this is written for PHP, the same principles apply for other languages. See the associated API reference pages for info on other languages.

The easiest way to get started is to run Bitcoin in daemon mode with which PHP communicates via local HTTP requests. A library called JSON-RPC is used to call the various functions of bitcoind, which will respond back with a JSON object.

It is however recommended to use one of the Alternative Libraries listed below instead, since they are more sophisticated.

Setting up Bitcoin

You can download the Bitcoin daemon from the homepage and run one of the included binaries or compile your own from the included source code. See Running Bitcoin for details on configuring bitcoind.

Before running bitcoind you will need to create a configuration file in the Bitcoin data directory (~/.bitcoin/bitcoin.conf on Linux):

rpcuser=user
rpcpassword={you MUST pick a unique password to be secure}

If you miss this step, bitcoind will remind you.

Now run bitcoind:

$ ./bitcoind
# wait a few seconds for it to start up
$ ./bitcoin-cli getblockchaininfo
# various information will be shown. If you get an error, try again until you see some useful output.
$ ./bitcoin-cli help
# get help on commands, note no dash before help

Bitcoin will begin synchronizing with the network and downloading a complete copy of the block chain. As of August 2012, more than 2gb of data must be downloaded and verified during this process. It may take two or more hours to complete. You will know when it's done when the block count reaches the current count.

Getblockchaininfo (Bitcoind's version of Hello World)

Assuming Bitcoin has finished the initialisation process; download the file jsonRPCClient.php from JSON-RPC PHP and place it in a web-accessible location.

Second, create a PHP file with the following and visit it with your browser to test.

  require_once 'jsonRPCClient.php';
  
  $bitcoin = new jsonRPCClient('http://user:password@127.0.0.1:8332/');
   
  echo "<pre>\n";
  print_r($bitcoin->getblockchaininfo());
  echo "</pre>";

Note: The jsonRPCClient library uses fopen() and will throw an exception saying "Unable to connect" if it receives a 404 or 500 error from bitcoind. This prevents you from being able to see error messages generated by bitcoind (as they are sent with status 404 or 500). The Alternative Libraries listed below are similar in function to JSON-RPC PHP but do not have this issue.

Precision

Bitcoin amounts can range from 1 Satoshi (0.00000001 BTC) to nearly 2,100,000,000,000,000 (21,000,000 BTC). To avoid rounding errors, you must make sure your PHP implementation supports the full range of Bitcoin values without losing precision. Most PHP implementations use IEEE 64-bit double-precision floating point numbers with 53 bits of precision, which is enough to correctly represent the full range of bitcoin values.

See Proper Money Handling (JSON-RPC) for more information.

If your PHP implementation does not support 64-bit numbers (again, this is very rare), you must use a version of bitcoind that sends values as strings (genjix maintains a fork at http://github.com/genjix/bitcoin) and use the GMP and BC Math libraries for all calculations involving bitcoin amounts.

Accounts

In Bitcoin, money is sent to addresses and many addresses can be held by one wallet. The balance shown by default in bitcoind is the sum of the bitcoins in all the addresses in the wallet.

Bitcoin goes another step. You can have accounts. Each account holds multiple addresses and acts like a mini-bitcoind.

$ ./bitcoin-cli listaccounts
# show list of accounts and various info for each one
$ ./bitcoin-cli getaccountaddress user889
# get an address to receive money to that is unique for the account user889
$ ./bitcoin-cli getbalance user889
# get the sum of all the money in the addresses owned by the account user889

In your application, each user should have a unique username. You may then query bitcoind for a unique address using $bitcoin->getaccountaddress("user889"); [gets the first address for user889] or $bitcoin->getnewaddress("user889"); [creates a new address for user889].

The customer then deposits to this address.

You can check the funds for that customer by doing $bitcoin->getbalance("user889", 4);. The 4 indicates the minimum number of confirmations we will accept before assuming this payment is valid.

If you will be using accounts for multiple deposits and withdrawals long-term, you may want to consider tracking user balances in your own database. This simplifies transfers between your application's accounts and decouples your accounts from the Bitcoin wallet.

getnewaddress vs getaccountaddress

Using getnewaddress helps increase maintain anonymity of your users by making it hard for a malicious agent to track payments flowing through your application. Running getnewaddress too often, however, will cause your wallet to become filled with many empty addresses.

It is therefore recommended to in some way limit the number of unfunded addresses each user can request. Here is an example using sessions:

<?php
    require_once('jsonRPCClient.php');
    $bitcoin = new jsonRPCClient('http://root:root@127.0.0.1:8332/'); 
    # now check for appropriate funds in user account
    try {
        $username = ...
        if(isset($_SESSION['sendaddress']))
            $sendaddress = $_SESSION['sendaddress'];
        else {
            $sendaddress = $bitcoin->getnewaddress($username);
            $_SESSION['sendaddress'] = $sendaddress;
        }
        $balance = $bitcoin->getbalance($username);
    }
    catch (Exception $e) {
        die("<p>Server error! Please contact the admin.</p>");
    }
?>

This creates a new address at the beginning of every new session, and stores it in the session variable.

Alternative Libs For RPC

There are alternative PHP libraries for connecting to the bitcoind RPC which are recommended over using the plain jsonRPCClient.php class. They do not rely on magic __call, use cURL instead of fopen and have better error handling (and can be installed using composer).

Alternative CLI clients

  • jsonrpc-cli provides simple jsonrpc queries from the command-line with highlighted json results (colors) and the ability to view/debug raw http requests and responses. It can also display json results in php print_r, var_dump, serialize formats as well as yaml.

See Also