function createPaymentRequest($params, &$formErrors) { $memcache = new Memcache(); $memcache->connect('localhost', 11211) or die("Could not connect to memcache"); // $params contains: // merchant / address123 / amount123 / time / expires / memo // payment_url / ACK_message $codec = new \DrSlump\Protobuf\Codec\Binary(); $details = new \payments\PaymentDetails(); $details->setTime(time() + (int) $params['time']); if ($params['expires'] != "never") { $details->setExpires(time() + (int) $params['expires']); } setField($params, 'memo', array($details, 'setMemo')); $testnet = false; $totalAmount = 0; $nAddresses = 0; for ($i = 1; $i <= 3; $i++) { $field = "address" . $i; if (!empty($params[$field])) { $output = new \payments\Output(); $r = address_to_script($params[$field]); if ($r === false) { $script = pubkeys_to_script($params[$field]); if ($script === false) { $formErrors[$field] = "Invalid address/pubkey"; continue; } $r = array(true, $script); } $testnet = $r[0]; $output->setScript($r[1]); $output->setAmount($params["amount" . $i] * 100000000.0); $totalAmount += $params["amount" . $i]; $nAddresses += 1; $details->addOutputs($output); // Testnet only, we don't want anybody to be able to create // real-money payment requests // from bitcoincore.org/gavinandresen@gmail.com: if (!$testnet && $params['merchant'] != "None") { $formErrors[$field] = "Testnet-only addresses, please"; return NULL; } } } if ($testnet) { $details->setNetwork("test"); } if (isset($params['payment_url'])) { /* Generate a unique id for this request: */ $id = uniqid(mySecret($memcache)); /* ... store it in merchant data: */ $details->setMerchantData($id); $ackURL = AbsoluteURL('') . "payACK.php"; $details->setPaymentUrl($ackURL); if (isset($params['ACK_message'])) { $memcache->set($id, $params['ACK_message'], 0, 60 * 60 * 24); } else { $memcache->set($id, '', 0, 60 * 60 * 24); } } $paymentRequest = new \payments\PaymentRequest(); $serialized = $details->serialize($codec); $paymentRequest->setSerializedPaymentDetails($serialized); // Signed? if ($params['merchant'] != "None") { $certK = $params['merchant'] . "certificate"; $keyK = $params['merchant'] . "key"; $certChain = new \payments\X509Certificates(); $cachedCertChain = $memcache->get($certK); if ($cachedCertChain === FALSE) { $leafCert = file_get_contents("/home/gavin/.certs/" . $params['merchant'] . ".crt"); $certs = fetch_chain($leafCert); foreach ($certs as $cert) { $certChain->addCertificate($cert); } $cachedCertChain = $certChain->serialize($codec); $memcache->set($certK, $cachedCertChain); } else { $certChain->parse($cachedCertChain); } $paymentRequest->setPkiType("x509+sha1"); $paymentRequest->setPkiData($certChain->serialize($codec)); $priv_key = file_get_contents("/home/gavin/.certs/" . $params['merchant'] . ".key"); $pkeyid = openssl_get_privatekey($priv_key); $paymentRequest->setSignature(""); $dataToSign = $paymentRequest->serialize($codec); $signature = ""; $result = openssl_sign($dataToSign, $signature, $pkeyid, OPENSSL_ALGO_SHA1); if ($signature === FALSE) { return "ERROR: signing failed.\n"; } $paymentRequest->setSignature($signature); } $data = $paymentRequest->serialize($codec); if (isset($params['produce_uri'])) { $urlParams = array(); $hash = hash('ripemd128', $data); $memcache->set($hash, $data, FALSE, 60 * 60 * 24); /* cache for 24 hours */ // f.php is fetch payment request from memcache: $urlParams['r'] = AbsoluteURL('') . "f.php?h=" . $hash; if ($nAddresses == 1 && $totalAmount > 0) { $urlParams['amount'] = $totalAmount; } if ($nAddresses == 1) { $url = AddArgsToURL("bitcoin:" . $params["address1"], $urlParams); } else { $url = AddArgsToURL("bitcoin:", $urlParams); } return MakeAnchor("CLICK TO PAY", $url); } header('Content-Type: application/bitcoin-paymentrequest'); $filename = "r" . (string) time() . ".bitcoinpaymentrequest"; header('Content-Disposition: inline; filename=' . $filename); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); header('Content-Length: ' . (string) strlen($data)); echo $data; exit(0); }
memo= : message to user expires= : unix timestamp (integer) when this Request expires payment_url= : URL where a Payment message should be sent out= : file to write to (default: standard output) USAGE; // Protocol buffer stuff: require_once 'DrSlump/Protobuf.php'; \DrSlump\Protobuf::autoload(); require_once 'paymentrequest.php'; // Certificate handling stuff: require_once 'certificates.php'; // Bitcoin address stuff: require_once 'base58.php'; $details = new \payments\PaymentDetails(); $details->setTime(time()); $paymentRequest = new \payments\PaymentRequest(); $payto = NULL; $amount = NULL; $certificate = NULL; $privatekey = NULL; $outfile = NULL; for ($i = 1; $i < $argc; $i++) { $keyval = explode("=", $argv[$i]); if (count($keyval) != 2) { echo "Unrecognized argument: " . $argv[$i] . "\n"; echo $usage; exit(1); } $key = trim($keyval[0], "-"); $val = $keyval[1];