fjffk简单的咖啡店科开发2方法2 环滁皆山也。其西南诸峰,林壑尤美,望之蔚然而深秀者,琅琊也。山行六七里,渐闻水声潺潺,而泻出于两峰之间者,酿泉也 ??????????????????????????????? ??????????????/????????????????? ............/................... .........................../... ??????????????????????????????? >>>>>>>>>>>>>/>>>>>>>>>>>>>>>>> ÿØÿà JFIF    ÿÛ „  ( %!1!%)+//.383,7(-.+  -%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ  ¥2" ÿÄ     ÿÄ J    ! 1AQ"aq2‘#BR‚¡ÁÑ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ   ÿÄ *  !1AQa‘"2q3±ð#b¡ÿÚ   ? ¼QxJQaÍuò¸Zö Úü8,ÐÚú "SSn<rçù–´âE—^ªBÖ9À\†¸ÔÁT­ÃÛ5 ëd´³Í#Ý;Þ38œî ¶H£M:wÎ3…³…âpÔF&‚FK¸9„â4àGEõªfÿ ‘ñ(ßw­pŽF|È¥ù®häðÍѶ¹‘[ÒinÙW¶ùñY˜Q{›K"išÒ[Ú8žë\F¹@-?v"ÔU”,ìöžkÿ {I‡£šÍ?e ríV ?> ......................................... ............................................................................. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>/>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ppphp-client/package.json000075500000001566152503640360011114 0ustar00{ "name": "php-bitpay-client", "description": "PHP Client Library for the BitPay Bitcoin Payment Gateway", "directories": { "lib": "src", "doc": "docs", "example": "examples", "test": "tests" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "https://github.com/bitpay/php-bitpay-client.git" }, "keywords": [ "bitpay", "bitcoin", "php", "library", "payment", "gateway", "ecommerce", "merchant", "money" ], "author": "BitPay Integrations Development Team", "license": "MIT", "bugs": { "url": "https://github.com/bitpay/php-bitpay-client/issues" }, "homepage": "https://github.com/bitpay/php-bitpay-client", "engines": { "node": ">=0.10.33", "npm": "~2.1.5" }, "devDependencies": { "phantomjs": "^1.9.12" } } php-client/build.xml000075500000002317152503640360010442 0ustar00 php-client/VERSION000075500000000011152503640360007656 0ustar003.0.0-p1 php-client/CHANGELOG.md000075500000006516152503640360010437 0ustar00# Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased][unreleased] ## [3.0.0] - 2016-03-10 ###Fixed - should respect that numbers coming from the api might not have decimal points at all, but they are still valid - Bug fixes that include proper type checking for invoice object creation - Fixed invoice, expiration, and current time error - Repaired tests based on current changes to the code. ###Added - Using this library with Symfony >=2.3 or Symfony 3.0.x should work. So if you are already using Symfony 3.0, then this library should work with it too. - Leo Hochberg added PaymentUrl support to the library since the BitPay backend support it. Thanks Leo. ## [2.2.7] - 2015-10-28 ###Fixed - btcPaid on invoice responses now contains the amount paid instead of the price ## [2.2.6] - 2015-07-31 ###Fixed - The fixes several issues, including "Price only accepts .00 precision" and "Invoice exception state" ### Changed - Refactored function calls out of loops ## [2.2.5] - 2015-06-23 ### Fixed - Item::setPrice accepts en_US formatted numeric strings - getInvoice now works with merchant and public facades ## [2.2.4] - 2015-06-04 ### Added - Token functionality for client-sided pairing - Set payout bitcoin amount, as returned by BitPay - Utility method for checking requirements - Autoloader documentation ### Changed - Documentation from RST to Markdown - Autoloader now loads relative to library root directory - Client now sets invoice tokens upon creation and retrieval ## [2.2.3] - 2015-05-29 ### Fixed - BitPay API errors are now passthrough ## [2.2.2] - 2015-01-13 ### Added - Mink/Behat testing ### Fixed - Corrected behavior of Math::mod ## [2.2.1] - 2014-12-10 ### Added - Payroll feature - Detailed tutorials ### Fixed - Math Engine issues - Stalling tests ## [2.2.0] - 2014-11-21 ### Changed - No longer solely depends on GMP for big integer math. Can now use BCMath as well ## [2.1.1] - 2014-11-19 ### Changed - Encrypted file storage is now default persistance for keys ### Fixed - McryptExtensionTest no longer fails randomly ### Removed - PHP 5.3 support. Now requires PHP >= 5.4 ## [2.1.0] - 2014-11-10 ### Added - Code Coverage tools - Integration testing - CA Bundle for Curl Adapter - Additional invoice tests - PEM Encoding and Decoding - Storage Class tutorial - `fullNotifications` for invoices ### Changed - Point arrays to objects - Better exception handling for Curl errors - Refactored `isGenerated` ### Fixed - MCrypt cipher type default is now a valid cipher type ## 2.0.0 - 2014-09-27 ### Changed - Client library now uses BitPay's new API [unreleased]: https://github.com/bitpay/php-bitpay-client/compare/v2.2.5...HEAD [2.2.5]: https://github.com/bitpay/php-bitpay-client/compare/v2.2.4...v2.2.5 [2.2.4]: https://github.com/bitpay/php-bitpay-client/compare/v2.2.3...v2.2.4 [2.2.3]: https://github.com/bitpay/php-bitpay-client/compare/v2.2.2...v2.2.3 [2.2.2]: https://github.com/bitpay/php-bitpay-client/compare/v2.2.1...v2.2.2 [2.2.1]: https://github.com/bitpay/php-bitpay-client/compare/v2.2.0...v2.2.1 [2.2.0]: https://github.com/bitpay/php-bitpay-client/compare/v2.1.1...v2.2.0 [2.1.1]: https://github.com/bitpay/php-bitpay-client/compare/v2.1.0...v2.1.1 [2.1.0]: https://github.com/bitpay/php-bitpay-client/compare/v2.0.0...v2.1.0 php-client/integration_tests.sh000075500000004046152503640360012723 0ustar00#!/usr/bin/env bash set_variables () { while true do read -p "Input Email: " EMAIL regex="^[a-z0-9!#\$%&'*+/=?^_\`{|}~-]+(\.[a-z0-9!#$%&'*+/=?^_\`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?\$"; if [[ "$EMAIL" =~ $regex ]] then export BITPAY_EMAIL=$EMAIL break else echo "Please input a valid email" fi done while true do read -p "Input Password: " PASSWORD read -p "Password Confirmation: " PASSWORD2 if [ "$PASSWORD" = "$PASSWORD2" ] then break else echo "Please input a valid password" fi done while true do read -p "Input URL: " URL if [ -z $URL ] then echo "Please input a valid URL" else break fi done } if [ -z "$1" ] then echo "No parameters passed so using Environment Variables" if [ -z "$BITPAY_EMAIL" ] || [ -z "$BITPAY_PASSWORD"] then echo "ERROR: No Email or password are set." echo "set BITPAY_EMAIL and BITPAY_PASSWORD as environment variables" echo "or pass them as arguments when running this script" while true; do read -p "Do you wish to set your environment variables here? " yn case $yn in [Yy]* ) set_variables; break;; [Nn]* ) echo "Closing script"; exit;; * ) echo "Please answer yes or no.";; esac done else echo "Environment Variables already exist for BITPAY." fi else echo "Username $1 and Password $2 passed from command line" URL=$1 EMAIL=$2 PASSWORD=$3 echo "Setting user and Password to new environment variables..." fi export BITPAY_EMAIL=$EMAIL export BITPAY_PASSWORD=$PASSWORD export BITPAY_URL=$URL echo "Using Email: $EMAIL" echo "Using URL: $URL" echo "Removing old keys..." if [ -e /tmp/bitpay.pub ] then rm -rf /tmp/bitpay.pub rm -rf /tmp/bitpay.pri rm -rf /tmp/token.json fi echo "Checking if Selenium exists..." if [ ! -f selenium-server-standalone-2.44.0.jar ] then echo "Downloading Selenium" curl -O http://selenium-release.storage.googleapis.com/2.44/selenium-server-standalone-2.44.0.jar fi echo "Running Selenium and the tests" php bin/behat tests/integrationsphp-client/behat.yml000075500000001156152503640360010427 0ustar00# behat.yml default: context: parameters: user: password: base_url: driver: 'selenium2' paths: features: tests/integrations bootstrap: %behat.paths.features%/bootstrap extensions: Behat\MinkExtension\Extension: goutte: ~ selenium2: ~ phantomjs: context: parameters: user: password: base_url: driver: 'phantomjs' paths: features: tests/integrations bootstrap: %behat.paths.features%/bootstrap extensions: Behat\MinkExtension\Extension: goutte: ~ selenium2: wd_host: "http://localhost:8643/wd/hub" php-client/src/Bitpay/Util/Util.php000075500000031063152503640360013203 0ustar00 0) { $q = Math::div($dec, '16'); $rem = Math::mod($dec, '16'); $dec = $q; $hex = substr(self::HEX_CHARS, intval($rem), 1) . $hex; } return $hex; } /** * Decodes a hexadecimal value into decimal. * * @param string $hex * @return string * @throws \Exception */ public static function decodeHex($hex) { if (!is_string($hex) || !ctype_xdigit($hex) && '0x' != substr($hex, 0, 2)) { throw new \Exception('Argument must be a string of hex digits.'); } $hex = strtolower(trim($hex)); // if it has a prefix of 0x this needs to be trimed if (substr($hex, 0, 2) == '0x') { $hex = substr($hex, 2); } $hexLen = strlen($hex); for ($dec = '0', $i = 0; $i < $hexLen; $i++) { $current = strpos(self::HEX_CHARS, $hex[$i]); $dec = Math::add(Math::mul($dec, '16'), $current); } return $dec; } /** * Calculates a new EC curve point. * * @param string $hex * @param PointInterface $point * @param CurveParameterInterface $parameters * @return Point */ public static function doubleAndAdd($hex, PointInterface $point, CurveParameterInterface $parameters = null) { if (null === $parameters) { $parameters = new Secp256k1(); } $tmp = self::decToBin($hex); $n = strlen($tmp) - 1; $S = new Point(PointInterface::INFINITY, PointInterface::INFINITY); while ($n >= 0) { $S = self::pointDouble($S); if ($tmp[$n] == 1) { $S = self::pointAdd($S, $point); } $n--; } return new Point($S->getX(), $S->getY()); } /** * This method returns a binary string representation of * the decimal number. Used for the doubleAndAdd() method. * * @see http://php.net/manual/en/function.decbin.php (but for large numbers) * @param string $dec * @return string $bin */ public static function decToBin($dec) { if (substr(strtolower($dec), 0, 2) == '0x') { $dec = self::decodeHex(substr($dec, 2)); } $bin = ''; while (Math::cmp($dec, '0') > 0) { if (Math::mod($dec, '2') == '1') { $bin .= '1'; } else { $bin .= '0'; } $dec = Math::div($dec, '2'); } return $bin; } /** * Point multiplication method 2P = R where * s = (3xP2 + a)/(2yP) mod p * xR = s2 - 2xP mod p * yR = -yP + s(xP - xR) mod p * * @param PointInterface $point * @param CurveParameterInterface $parameters * @return PointInterface * @throws \Exception */ public static function pointDouble(PointInterface $point, CurveParameterInterface $parameters = null) { if ($point->isInfinity()) { return $point; } if (null === $parameters) { $parameters = new Secp256k1(); } $p = $parameters->pHex(); $a = $parameters->aHex(); $s = 0; $R = array( 'x' => 0, 'y' => 0, ); // Critical math section try { $m = Math::add(Math::mul(3, Math::mul($point->getX(), $point->getX())), $a); $o = Math::mul('2', $point->getY()); $n = Math::invertm($o, $p); $n2 = Math::mod($o, $p); $st = Math::mul($m, $n); $st2 = Math::mul($m, $n2); $s = Math::mod($st, $p); $s2 = Math::mod($st2, $p); $xmul = Math::mul('2', $point->getX()); $smul = Math::mul($s, $s); $xsub = Math::sub($smul, $xmul); $xmod = Math::mod($xsub, $p); $R['x'] = $xmod; $ysub = Math::sub($point->getX(), $R['x']); $ymul = Math::mul($s, $ysub); $ysub2 = Math::sub('0', $point->getY()); $yadd = Math::add($ysub2, $ymul); $R['y'] = Math::mod($yadd, $p); } catch (\Exception $e) { throw new \Exception('Error in Util::pointDouble(): ' . $e->getMessage()); } return new Point($R['x'], $R['y']); } /** * Point addition method P + Q = R where: * s = (yP - yQ)/(xP - xQ) mod p * xR = s2 - xP - xQ mod p * yR = -yP + s(xP - xR) mod p * * @param PointInterface $P * @param PointInterface $Q * @return PointInterface */ public static function pointAdd(PointInterface $P, PointInterface $Q) { if ($P->isInfinity()) { return $Q; } if ($Q->isInfinity()) { return $P; } if ($P->getX() == $Q->getX() && $P->getY() == $Q->getY()) { return self::pointDouble(new Point($P->getX(), $P->getY())); } $p = '0x' . Secp256k1::P; $a = '0x' . Secp256k1::A; $s = 0; $R = array( 'x' => 0, 'y' => 0, 's' => 0, ); // Critical math section try { $m = Math::sub($P->getY(), $Q->getY()); $n = Math::sub($P->getX(), $Q->getX()); $o = Math::invertm($n, $p); $st = Math::mul($m, $o); $s = Math::mod($st, $p); $R['x'] = Math::mod( Math::sub( Math::sub( Math::mul($s, $s), $P->getX() ), $Q->getX() ), $p ); $R['y'] = Math::mod( Math::add( Math::sub( '0', $P->getY() ), Math::mul( $s, Math::sub( $P->getX(), $R['x'] ) ) ), $p ); $R['s'] = $s; } catch (Exception $e) { throw new \Exception('Error in Util::pointAdd(): ' . $e->getMessage()); } return new Point($R['x'], $R['y']); } /** * Converts hex value into octet (byte) string. * * @param string $hex * @return string $byte */ public static function binConv($hex) { $rem = ''; $dv = ''; $byte = ''; $digits = array(); for ($x = 0; $x < 256; $x++) { $digits[$x] = chr($x); } if (substr(strtolower($hex), 0, 2) != '0x') { $hex = '0x' . strtolower(trim($hex)); } while (Math::cmp($hex, '0') > 0) { $dv = Math::div($hex, '256'); $rem = Math::mod($hex, '256'); $hex = $dv; $byte = $byte . $digits[$rem]; } return strrev($byte); } /** * Checks dependencies for the library. * * @return array list of each requirement, boolean true if met, string error message if not as value */ public static function checkRequirements() { $requirements = array(); // PHP Version if (!defined('PHP_VERSION_ID')) { $version = explode('.', PHP_VERSION); define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2])); } if (PHP_VERSION_ID < 50400) { $requirements['PHP'] = 'Your PHP version, ' . PHP_VERSION . ', is too low. PHP version >= 5.4 is required.'; } else { $requirements['PHP'] = true; } // OpenSSL Extension if (!extension_loaded('openssl')) { $requirements['OpenSSL'] = 'The OpenSSL PHP extension could not be found.'; } else { $requirements['OpenSSL'] = true; } // JSON Extension if (!extension_loaded('json')) { $requirements['JSON'] = 'The JSON PHP extension could not be found.'; } else { $requirements['JSON'] = true; } // cURL Extension if (!extension_loaded('curl')) { $requirements['cURL'] = 'The cURL PHP extension could not be found.'; } else { $requirements['cURL'] = true; $curl_version = curl_version(); $ssl_supported = ($curl_version['features'] & CURL_VERSION_SSL); if (!$ssl_supported) { $requirements['cURL.SSL'] = 'The cURL PHP extension does not have SSL support.'; } else { $requirements['cURL.SSL'] = true; } } // Math if (!extension_loaded('bcmath') && !extension_loaded('gmp')) { $requirements['Math'] = 'Either the BC Math or GMP PHP extension is required. Neither could be found.'; } else { $requirements['Math'] = true; } return $requirements; } } php-client/src/Bitpay/Util/Error.php000075500000010422152503640360013353 0ustar00= 4.3.0, PHP 5) * * @param bool * @param bool * @param int * @return array|void */ final public function backtrace($print = false, $options = false, $limit = 0) { if ($print == true) { return debug_print_backtrace($options, $limit); } else { return debug_backtrace($options, $limit); } } /** * Get the last occurred error and returns an associative * array describing the last error with keys "type", "message", * "file" and "line". If the error has been caused by a PHP * internal function then the "message" begins with its name. * Returns NULL if there hasn't been an error yet. * (PHP 5 >= 5.2.0) * * @param void * @return array */ final public function last() { return error_get_last(); } /** * Send an error message to the defined error handling * routines. Returns true on success or false on failure. * The possible values for $message_type are: 0 = system log, * 1 = email to $destination, 2 = depricated, 3 = appended * to file $destination, 4 = sent to SAPI log handler. * (PHP 4, PHP 5) * * @param string * @param int * @param string * @param string */ final public function log($message, $message_type = 0, $destination = '', $extra_headers = '') { return error_log((string) $message, $message_type = 0, $destination = '', $extra_headers = ''); } /** * Sets which PHP errors are reported or returns the old * error_reporting level or the current level if no level * parameter is given. * (PHP 4, PHP 5) * * @param bool * @return int */ final public function reporting($level = false) { if ($level !== false) { return error_reporting($level); } else { return error_reporting(); } } /** * Sets or restores either the error or exception handler * based on the $type and $action parameters. * (PHP 4 >= 4.0.1, PHP 5) * * @param string * @param string * @param mixed * @param int * return mixed */ final public function handler($type = 'error', $action = 'restore', $callable_handler = false, $error_types = null) { if (empty($error_types)) { $error_types = E_ALL | E_STRICT; } switch (strtolower($type)) { case 'error': switch (strtolower($action)) { case 'restore': return restore_error_handler(); break; case 'set': return set_error_handler($callable_handler, $error_types); break; default: return false; } break; case 'exception': switch (strtolower($action)) { case 'restore': return restore_exception_handler(); break; case 'set': return set_exception_handler($callable_handler); break; default: return false; } break; default: return false; } } /** * Generates a user-level error/warning/notice message. * This function returns FALSE if wrong $error_type is * specified, TRUE otherwise. The $error_msg param is * limited to 1024 bytes. * (PHP 4 >= 4.0.1, PHP 5) * * @param string * @param int * @return bool */ final public function raise($error_msg, $error_type = E_USER_NOTICE) { return trigger_error($error_msg, $error_type); } } php-client/src/Bitpay/Util/Base58.php000075500000004116152503640360013314 0ustar00 0) { $q = Math::div($x, '58'); $r = Math::mod($x, '58'); $output_string .= substr($code_string, intval($r), 1); $x = $q; } for ($i = 0; $i < $dataLen && substr($data, $i, 2) == '00'; $i += 2) { $output_string .= substr($code_string, 0, 1); } $output_string = strrev($output_string); return $output_string; } /** * Decodes a numeric string from BASE-58 format. * * @param string $data * @return string $return */ public static function decode($data) { $dataLen = strlen($data); for ($return = '0', $i = 0; $i < $dataLen; $i++) { $current = strpos(self::BASE58_CHARS, $data[$i]); $return = Math::mul($return, '58'); $return = Math::add($return, $current); } $return = Util::encodeHex($return); for ($i = 0; $i < $dataLen && substr($data, $i, 1) == '1'; $i++) { $return = '00' . $return; } if (strlen($return) % 2 != 0) { $return = '0' . $return; } return $return; } } php-client/src/Bitpay/Util/CurveParameterInterface.php000075500000000657152503640360017041 0ustar00 $v) { if (in_array(strtolower($k), $serverVariables)) { self::$sigData[] = $v; } } self::$sigData[] = phpversion(); self::$sigData[] = get_current_user(); self::$sigData[] = php_uname('s') . php_uname('n') . php_uname('m') . PHP_OS . PHP_SAPI . ICONV_IMPL . ICONV_VERSION; self::$sigData[] = sha1_file(__FILE__); self::$finHash = implode(self::$sigData); self::$finHash = sha1(str_ireplace(' ', '', self::$finHash) . strlen(self::$finHash) . metaphone(self::$finHash)); self::$finHash = sha1(self::$finHash); return self::$finHash; } } php-client/src/Bitpay/Util/Secp256k1.php000075500000002701152503640360013646 0ustar00txid; } /** * Set transaction ID for payout. * @param $txid * @return $this */ public function setTransactionId($txid) { if (!empty($txid)) { $this->txid = $txid; } return $this; } /** * @inheritdoc */ public function getAmount() { return $this->amount; } /** * Set the amount of bitcoin paid in the paout. * @param $amount * @return $this */ public function setAmount($amount) { if (!empty($amount)) { $this->amount = $amount; } return $this; } /** * @inheritdoc */ public function getDate() { return $this->date; } /** * Set the date and time of when the payment was sent. * @param $date * @return $this */ public function setDate($date) { if (!empty($date)) { $this->date = $date; } return $this; } } php-client/src/Bitpay/Token.php000075500000005725152503640360012437 0ustar00policies = array(); } /** * @return string */ public function __toString() { return (string)$this->getToken(); } /** * @return string */ public function getToken() { return $this->token; } /** * @param string * @return Token */ public function setToken($token) { $this->token = $token; return $this; } /** * @return string */ public function getResource() { return $this->resource; } /** * @param string * @return Token */ public function setResource($resource) { $this->resource = $resource; return $this; } /** * @return string */ public function getFacade() { return $this->facade; } /** * @param string * @return Token */ public function setFacade($facade) { $this->facade = $facade; return $this; } /** * @return \DateTime */ public function getCreatedAt() { return $this->createdAt; } /** * @param \DateTime * @return Token */ public function setCreatedAt(\DateTime $createdAt) { $this->createdAt = $createdAt; return $this; } /** * @return array */ public function getPolicies() { return $this->policies; } /** * @param string * @return Token */ public function setPolicies($policies) { $this->policies = $policies; return $this; } /** * @return string */ public function getPairingCode() { return $this->pairingCode; } /** * @param string * @return Token */ public function setPairingCode($pairingCode) { $this->pairingCode = $pairingCode; return $this; } /** * @return \DateTime */ public function getPairingExpiration() { return $this->pairingExpiration; } /** * @param \DateTime * @return Token */ public function setPairingExpiration(\DateTime $pairingExpiration) { $this->pairingExpiration = $pairingExpiration; return $this; } } php-client/src/Bitpay/TokenInterface.php000075500000001360152503640360014247 0ustar00password = $password; } /** * @inheritdoc */ public function persist(\Bitpay\KeyInterface $key) { $path = $key->getId(); $data = serialize($key); $encrypted = $this->dataEncrypt($data); $encoded = $this->dataEncode($encrypted); $this->saveToFile($encoded, $path); } /** * @inheritdoc */ public function load($id) { $encoded = $this->readFromFile($id); $decoded = $this->dataDecode($encoded); $decrypted = $this->dataDecrypt($decoded); return unserialize($decrypted); } /** * @param string $data * @return string * @throws \Exception */ private function dataEncrypt($data) { $encrypted = openssl_encrypt($data, self::METHOD, $this->password, self::OPENSSL_RAW_DATA, self::IV); if ($encrypted === false) { throw new \Exception('[ERROR] In EncryptedFilesystemStorage::dataEncrypt(): Could not encrypt data "' . $data . '". OpenSSL error(s) are: "' . $this->getOpenSslErrors() . '".'); } return $encrypted; } /** * @param string $data * @return string * @throws \Exception */ private function dataDecrypt($data) { $decrypted = openssl_decrypt($data, self::METHOD, $this->password, self::OPENSSL_RAW_DATA, self::IV); if ($decrypted === false) { throw new \Exception('[ERROR] In EncryptedFilesystemStorage::dataDecrypt(): Could not decrypt data "' . $data . '". OpenSSL error(s) are: "' . $this->getOpenSslErrors() . '".'); } return $decrypted; } /** * @param string $data * @return string * @throws \Exception */ private function dataEncode($data) { $encoded = base64_encode($data); if ($encoded === false) { throw new \Exception('[ERROR] In EncryptedFilesystemStorage::dataEncode(): Could not encode data "' . $data . '".'); } return $encoded; } /** * @param string $data * @return string * @throws \Exception */ private function dataDecode($data) { $decoded = base64_decode($data); if ($decoded === false) { throw new \Exception('[ERROR] In EncryptedFilesystemStorage::dataDecode(): Could not decode data "' . $data . '".'); } return $decoded; } /** * @param string $data * @param string $path * @throws \Exception */ private function saveToFile($data, $path) { if (file_put_contents($path, $data) === false) { throw new \Exception('[ERROR] In EncryptedFilesystemStorage::saveToFile(): Could not write to the file "' . $path . '".'); } } /** * @param string $path * @return string * @throws \Exception */ private function readFromFile($path) { if (is_file($path) === false || is_readable($path) === false) { throw new \Exception('[ERROR] In EncryptedFilesystemStorage::readFromFile(): The file "' . $path . '" does not exist or cannot be read, check permissions.'); } $data = file_get_contents($path); if ($data === false) { throw new \Exception('[ERROR] In EncryptedFilesystemStorage::readFromFile(): The file "' . $path . '" cannot be read, check permissions.'); } return $data; } /** * @return string */ private function getOpenSslErrors() { $openssl_error_msg = ''; while ($msg = openssl_error_string()) { $openssl_error_msg .= $msg . "\r\n"; } return $openssl_error_msg; } } php-client/src/Bitpay/Storage/StorageInterface.php000075500000000661152503640360016202 0ustar00getId(); file_put_contents($path, serialize($key)); } catch (\Exception $e) { throw new \Exception('[ERROR] In FilesystemStorage::persist(): ' . $e->getMessage()); } } /** * @inheritdoc */ public function load($id) { if (!is_file($id)) { throw new \Exception(sprintf('[ERROR] In FilesystemStorage::load(): Could not find "%s".', $id)); } if (!is_readable($id)) { throw new \Exception(sprintf('[ERROR] In FilesystemStorage::load(): "%s" cannot be read, check permissions.', $id)); } return unserialize(file_get_contents($id)); } } php-client/src/Bitpay/AccessToken.php000075500000003511152503640360013550 0ustar00id = $id; $this->email = $email; $this->label = $label; } /** * Setter for the id. * * @param string $id * @return AccessToken */ public function setId($id) { if (!empty($id) && is_string($id) && ctype_print($id)) { $this->id = trim($id); } return $this; } /** * @inheritdoc */ public function getId() { return $this->id; } /** * Setter for the email address. * * @param string $email * @return AccessToken */ public function setEmail($email) { if (!empty($email) && is_string($email) && ctype_print($email)) { $this->email = trim($email); } return $this; } /** * @inheritdoc */ public function getEmail() { return $this->email; } /** * Setter for the label. * * @param string $label * @return AccessToken */ public function setLabel($label) { if (!empty($label) && is_string($label) && ctype_print($label)) { $this->label = trim($label); } return $this; } /** * @inheritdoc */ public function getLabel() { return $this->label; } } php-client/src/Bitpay/ItemInterface.php000075500000002001152503640360014056 0ustar00x)) { return ''; } if (Math::mod('0x'.$this->y, '0x02') == '1') { return sprintf('03%s', $this->x); } else { return sprintf('02%s', $this->x); } } /** * @param PrivateKey * @return PublicKey */ public static function createFromPrivateKey(PrivateKey $private) { $public = new self(); $public->setPrivateKey($private); return $public; } /** * @param PrivateKey * @return PublicKey */ public function setPrivateKey(PrivateKey $privateKey) { $this->privateKey = $privateKey; return $this; } /** * Generates an uncompressed and compressed EC public key. * * @param \Bitpay\PrivateKey $privateKey * @return \Bitpay\PublicKey * @throws \Exception */ public function generate(PrivateKey $privateKey = null) { if ($privateKey instanceof PrivateKey) { $this->setPrivateKey($privateKey); } if (!empty($this->hex)) { return $this; } if (is_null($this->privateKey)) { throw new \Exception('Please `setPrivateKey` before you generate a public key'); } if (!$this->privateKey->isGenerated()) { $this->privateKey->generate(); } if (!$this->privateKey->isValid()) { throw new \Exception('Private Key is invalid and cannot be used to generate a public key'); } $point = new Point( '0x'.substr(Secp256k1::G, 2, 64), '0x'.substr(Secp256k1::G, 66, 64) ); $R = Util::doubleAndAdd( '0x'.$this->privateKey->getHex(), $point ); $RxHex = Util::encodeHex($R->getX()); $RyHex = Util::encodeHex($R->getY()); $RxHex = str_pad($RxHex, 64, '0', STR_PAD_LEFT); $RyHex = str_pad($RyHex, 64, '0', STR_PAD_LEFT); $this->x = $RxHex; $this->y = $RyHex; $this->hex = sprintf('%s%s', $RxHex, $RyHex); $this->dec = Util::decodeHex($this->hex); return $this; } /** * Checks to see if the public key is not blank and contains * valid decimal and hex valules for this->hex & this->dec * * @return boolean */ public function isValid() { return ((!empty($this->hex) && ctype_xdigit($this->hex)) && (!empty($this->dec) && ctype_digit($this->dec))); } /** * @return SinKey */ public function getSin() { if (empty($this->hex)) { $this->generate(); } if (null === $this->sin) { $this->sin = new SinKey(); $this->sin->setPublicKey($this); $this->sin->generate(); } return $this->sin; } } php-client/src/Bitpay/Point.php000075500000003004152503640360012434 0ustar00x = (string) $x; $this->y = (string) $y; } /** * @return string */ public function __toString() { if ($this->isInfinity()) { return self::INFINITY; } return sprintf('(%s, %s)', $this->x, $this->y); } /** * @return string */ public function getX() { return $this->x; } /** * @return string */ public function getY() { return $this->y; } /** * @return boolean */ public function isInfinity() { return (self::INFINITY == $this->x || self::INFINITY == $this->y); } /** * @inheritdoc */ public function serialize() { return serialize(array($this->x, $this->y)); } /** * @inheritdoc */ public function unserialize($data) { list( $this->x, $this->y ) = unserialize($data); } } php-client/src/Bitpay/Buyer.php000075500000000370152503640360012434 0ustar00storage = $storage; } /** * @param KeyInterface $key */ public function persist(KeyInterface $key) { $this->storage->persist($key); } /** * @return KeyInterface */ public function load($id) { return $this->storage->load($id); } } php-client/src/Bitpay/Math/BcEngine.php000075500000011126152503640360013712 0ustar00input($a); $b = $this->input($b); return bcadd($a, $b); } /** * @param String $a Numeric String * @param String $b Numeric String */ public function cmp($a, $b) { $a = $this->input($a); $b = $this->input($b); return bccomp($a, $b); } /** * @param String $a Numeric String * @param String $b Numeric String */ public function div($a, $b) { $a = $this->input($a); $b = $this->input($b); return bcdiv($a, $b); } /** * Finds inverse number $inv for $num by modulus $mod, such as: * $inv * $num = 1 (mod $mod) * * @param string $num * @param string $mod * @return string * @access public */ public function invertm($num, $mod) { $num = $this->input($num); $mod = $this->input($mod); $x = '1'; $y = '0'; $num1 = $mod; do { $tmp = bcmod($num, $num1); $q = bcdiv($num, $num1); $num = $num1; $num1 = $tmp; $tmp = bcsub($x, bcmul($y, $q)); $x = $y; $y = $tmp; } while (bccomp($num1, '0')); if (bccomp($x, '0') < 0) { $x = bcadd($x, $mod); } if (substr($num, 0, 1) === '-') { $x = bcsub($mod, $x); } return $x; } /** * @param String $a Numeric String * @param String $b Numeric String */ public function mod($a, $b) { $a = $this->input($a); $b = $this->input($b); if (substr($a, 0, 1) === '-') { return bcadd(bcmod($a, $b), $b); } return bcmod($a, $b); } /** * @param String $a Numeric String * @param String $b Numeric String */ public function mul($a, $b) { $a = $this->input($a); $b = $this->input($b); return bcmul($a, $b); } /** * @param String $a Numeric String * @param String $b Numeric String */ public function pow($a, $b) { $a = $this->input($a); $b = $this->input($b); return bcpow($a, $b); } /** * @param String $a Numeric String * @param String $b Numeric String */ public function sub($a, $b) { $a = $this->input($a); $b = $this->input($b); return bcsub($a, $b); } public function input($x) { if (empty($x)) { return '0'; } $x = strtolower(trim($x)); if (preg_match('/^(-?)0x([0-9a-f]+)$/', $x, $matches)) { $sign = $matches[1]; $hex = $matches[2]; for ($dec = '0', $i = 0; $i < strlen($hex); $i++) { $current = strpos('0123456789abcdef', $hex[$i]); $dec = bcadd(bcmul($dec, 16), $current); } return $sign.$dec; } elseif (preg_match('/^-?[0-9]+$/', $x)) { return $x; } else { throw new \Exception("The input must be a numeric string in decimal or hexadecimal (with leading 0x) format.\n".var_export($x, true)); } } /** * Function to determine if two numbers are * co-prime according to the Euclidean algo. * * @param string $a First param to check. * @param string $b Second param to check. * @return bool Whether the params are cp. */ public function coprime($a, $b) { $small = 0; $diff = 0; while (bccomp($a, '0') > 0 && bccomp($b, '0') > 0) { if (bccomp($a, $b) == -1) { $small = $a; $diff = bcmod($b, $a); } if (bccomp($a, $b) == 1) { $small = $b; $diff = bcmod($a, $b); } if (bccomp($a, $b) == 0) { $small = $a; $diff = bcmod($b, $a); } $a = $small; $b = $diff; } if (bccomp($a, '1') == 0) { return true; } return false; } } php-client/src/Bitpay/Math/GmpEngine.php000075500000003224152503640360014111 0ustar00 $digest_alg, 'private_key_bits' => (int) $keybits, 'private_key_type' => OPENSSL_KEYTYPE_RSA, ); $resource = openssl_pkey_new($config); if (!$resource) { throw new \Exception('Error in generateOpenSSLKeypair: Could not create new OpenSSL resource.'); /* with the openssl extension, you also have it's own errors returned */ while ($msg = openssl_error_string()) { throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL reported error: '.$msg); } return false; } if (openssl_pkey_export($resource, $keypair['pri'])) { $publickey = openssl_pkey_get_details($resource); $keypair['pub'] = $publickey['key']; } else { throw new \Exception('Error in generateOpenSSLKeypair: Private key could not be determined from OpenSSL key resource.'); while ($msg = openssl_error_string()) { throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL reported error: '.$msg); } return false; } openssl_pkey_free($resource); return $keypair; } else { throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL PHP extension missing. Cannot continue.'); return false; } } catch (Exception $e) { while ($msg = openssl_error_string()) { throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL reported error: '.$msg); } throw $e; return false; } } /** * Generates a high-quality random number suitable for * use in cryptographic functions and returns hex value. * * @param int * @return string|bool */ final public function randomNumber($bytes = 32) { $random_data = openssl_random_pseudo_bytes($bytes, $cstrong); if (!$cstrong || !$random_data) { return false; } else { return bin2hex($random_data); } } /** * Returns the cipher length on success, or FALSE * on failure. (PHP 5 >= PHP 5.3.3) * * @param string * @return int|bool */ final public function cypherIVLength($cypher = '') { return openssl_cipher_iv_length($cypher); } /** * Takes the Certificate Signing Request represented * by $csr and saves it as ascii-armoured text into * the file named by $outfilename. * (PHP 4 >= 4.2.0, PHP 5) * * @param resource * @param string * @param bool * @return bool */ final public function saveCSRtoFile($csr, $outfilename, $notext = true) { if (!is_resource($csr)) { return false; } return openssl_csr_export_to_file($csr, $outfilename, $notext); } /** * Takes the Certificate Signing Request represented * by $csr and stores it as ascii-armoured text into * $out, which is passed by reference. * (PHP 4 >= 4.2.0, PHP 5) * * @param resource * @param string * @param bool * @return bool */ final public function saveCSRtoString($csr, $out, $notext = true) { if (!is_resource($csr)) { return false; } return openssl_csr_export($csr, $out, $notext); } } php-client/src/Bitpay/Crypto/HashExtension.php000075500000014777152503640360015426 0ustar00= 5.1.2, PECL hash >= 1.1) * * @return array */ public function getAlgos() { return hash_algos(); } /** * Copy a hashing context. * (PHP 5 >= 5.3.0) * * @param resource * @return resource */ final public function copy($context) { if (!is_resource($context)) { return false; } return hash_copy($context); } /** * Compares two strings using the same time * whether they're equal or not. This function * should be used to mitigate timing attacks; * for instance, when testing crypt() password * hashes. * (PHP 5 >= 5.6.0) * * @param string * @param string */ public function equals($string1, $string2) { if (!is_string($string1) || !is_string($string2)) { return false; } return hash_equals($string1, $string2); } /** * Generate a hash value using the contents of * a given file. Returns a string containing * the calculated message digest as lowercase * hexits unless raw_output is set to true in * which case the raw binary representation of * the message digest is returned. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param string * @param string * @param bool * @return string */ public function file($algorithm, $filename, $raw_output = false) { return hash_file($algorithm, (string) $filename, $raw_output); } /** * Finalize an incremental hash and return * resulting digest. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param resource * @param bool * @return string */ public function finalize($context, $raw_output = false) { if (!is_resource($context)) { return false; } return hash_final($context, $raw_output); } /** * Generate a keyed hash value using the HMAC * method and the contents of a given file. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param string * @param string * @param string * @param bool * @return string */ public function hmacFile($algorithm, $filename, $key, $raw_output = false) { return hash_hmac_file($algorithm, $filename, $key, $raw_output); } /** * Generate a keyed hash value using the HMAC * method and the message passed via $data. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param string * @param string * @param string * @param bool * @return string */ public function hmac($algo, $data, $key, $raw_output = false) { return hash_hmac($algo, $data, $key, $raw_output); } /** * Initialize an incremental hashing context and * returns a Hashing Context resource for use with * hash_update(), hash_update_stream(), hash_update_file(), * and hash_final(). Note: the only option possible * for $options at this time is HASH_HMAC. When * this is specified, the key *must* be used as well. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param string * @param int * @param string * @return resource */ public function init($algorithm, $options = 0, $key = null) { return hash_init($algorithm, $options, $key); } /** * Generate a PBKDF2 key derivation of a supplied * password. An E_WARNING will be raised if the * algorithm is unknown, the iterations parameter * is less than or equal to 0, the length is less * than 0 or the salt is too long (greater than * INT_MAX - 4). The salt should be generated * randomly with openssl_ramdom_pseudo_bytes(). * (PHP 5 >= 5.5.0) * * @param string * @param string * @param string * @param int * @param int * @param bool * @return string */ public function pbkdf2($algo, $password, $salt, $iterations, $length = 0, $raw_output = false) { return hash_pbkdf2($algo, $password, $salt, $iterations, $length, $raw_output); } /** * Pump data into an active hashing context * from a file. Returns TRUE on success or * FALSE on failure. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param resource * @param string * @param resource * @return bool */ public function updateFile($hcontext, $filename, $scontext = null) { if (!is_resource($hcontext)) { return false; } return hash_update_file($hcontext, $filename, $scontext); } /** * Pump data into an active hashing context * from an open stream. Returns the actual * number of bytes added to the hashing * context from handle. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param resource * @param resource * @param int * @return int */ public function updateStream($context, $handle, $length = -1) { if (!is_resource($context) || !is_resource($handle)) { return false; } return hash_update_stream($context, $handle, $length); } /** * Pump data into an active hashing context. * The PHP function itself only returns true. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param resource * @param string * @return bool */ public function update($context, $data) { if (!is_resource($context)) { return false; } return hash_update($context, $data); } /** * Generate a hash value (message digest) * based on the request algorithm and the * provided data. Outputs hex unless the * $raw_output param is set to true. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param string * @param string * @param bool * @return string */ public function generate($algo, $data, $raw_output = false) { if (empty($data)) { return false; } return hash($algo, $data, $raw_output); } } php-client/src/Bitpay/Crypto/CryptoInterface.php000075500000001035152503640360015726 0ustar00phone; } /** * @param string $phone * @return User */ public function setPhone($phone) { if (!empty($phone) && is_string($phone) && ctype_print($phone)) { $this->phone = trim($phone); } return $this; } /** * @inheritdoc */ public function getEmail() { return $this->email; } /** * @param string $email * @return User */ public function setEmail($email) { if (!empty($email) && is_string($email) && ctype_print($email)) { $this->email = trim($email); } return $this; } /** * @inheritdoc */ public function getFirstName() { return $this->firstName; } /** * @param string $firstName * @return User */ public function setFirstName($firstName) { if (!empty($firstName) && is_string($firstName) && ctype_print($firstName)) { $this->firstName = trim($firstName); } return $this; } /** * @inheritdoc */ public function getLastName() { return $this->lastName; } /** * @param string $lastName * @return User */ public function setLastName($lastName) { if (!empty($lastName) && is_string($lastName) && ctype_print($lastName)) { $this->lastName = trim($lastName); } return $this; } /** * @inheritdoc */ public function getAddress() { return $this->address; } /** * @param array $address * @return User */ public function setAddress(array $address) { if (!empty($address) && is_array($address)) { $this->address = $address; } return $this; } /** * @inheritdoc */ public function getCity() { return $this->city; } /** * @param string $city * @return User */ public function setCity($city) { if (!empty($city) && is_string($city) && ctype_print($city)) { $this->city = trim($city); } return $this; } /** * @inheritdoc */ public function getState() { return $this->state; } /** * @param string $state * @return User */ public function setState($state) { if (!empty($state) && is_string($state) && ctype_print($state)) { $this->state = trim($state); } return $this; } /** * @inheritdoc */ public function getZip() { return $this->zip; } /** * @param string $zip * @return User */ public function setZip($zip) { if (!empty($zip) && is_string($zip) && ctype_print($zip)) { $this->zip = trim($zip); } return $this; } /** * @inheritdoc */ public function getCountry() { return $this->country; } /** * @param string $country * @return User */ public function setCountry($country) { if (!empty($country) && is_string($country) && ctype_print($country)) { $this->country = trim($country); } return $this; } /** * @param bool $boolvalue * @return User */ public function setAgreedToTOSandPP($boolvalue) { if (!empty($boolvalue)) { $this->agreedToTOSandPP = $boolvalue; } return $this; } /** * @return bool */ public function getAgreedToTOSandPP() { return $this->agreedToTOSandPP; } } php-client/src/Bitpay/PayoutTransactionInterface.php000075500000001173152503640360016660 0ustar00address = array(); $this->archived = false; $this->currency = new Currency(); $this->items = array(); } /** * @inheritdoc */ public function getItems() { return $this->items; } /** * @param Item $item * @return Bill */ public function addItem(Item $item) { if (!empty($item)) { $this->items[] = $item; } return $this; } /** * @inheritdoc */ public function getCurrency() { return $this->currency; } /** * @param Currency $currency * @return Bill */ public function setCurrency(Currency $currency) { if (!empty($currency)) { $this->currency = $currency; } return $this; } /** * @inheritdoc */ public function getName() { return $this->name; } /** * @param string $name * @return Bill */ public function setName($name) { if (!empty($name) && ctype_print($name)) { $this->name = trim($name); } return $this; } /** * @inheritdoc */ public function getAddress() { return $this->address; } /** * @param array $address * @return Bill */ public function setAddress($address) { if (!empty($address) && is_array($address)) { $this->address = $address; } return $this; } /** * @inheritdoc */ public function getCity() { return $this->city; } /** * @param string $city * @return Bill */ public function setCity($city) { if (!empty($city) && ctype_print($city)) { $this->city = trim($city); } return $this; } /** * @inheritdoc */ public function getState() { return $this->state; } /** * @param string $state * @return Bill */ public function setState($state) { if (!empty($state) && ctype_print($state)) { $this->state = trim($state); } return $this; } /** * @inheritdoc */ public function getZip() { return $this->zip; } /** * @param string $zip * @return Bill */ public function setZip($zip) { if (!empty($zip) && ctype_print($zip)) { $this->zip = trim($zip); } return $this; } /** * @inheritdoc */ public function getCountry() { return $this->country; } /** * @param string $country * @return Bill */ public function setCountry($country) { if (!empty($country) && ctype_print($country)) { $this->country = trim($country); } return $this; } /** * @inheritdoc */ public function getEmail() { return $this->email; } /** * @param string $email * @return Bill */ public function setEmail($email) { if (!empty($email) && ctype_print($email)) { $this->email = trim($email); } return $this; } /** * @inheritdoc */ public function getPhone() { return $this->phone; } /** * @param string $phone * @return Bill */ public function setPhone($phone) { if (!empty($phone) && ctype_print($phone)) { $this->phone = trim($phone); } return $this; } /** * @inheritdoc */ public function getStatus() { return $this->status; } /** * @param string $status * @return Bill */ public function setStatus($status) { if (!empty($status) && ctype_print($status)) { $this->status = trim($status); } return $this; } /** * @inheritdoc */ public function getShowRate() { return $this->showRate; } /** * @param string $showRate * @return Bill */ public function setShowRate($showRate) { if (!empty($showRate) && ctype_print($showRate)) { $this->showRate = trim($showRate); } return $this; } /** * @inheritdoc */ public function getArchived() { return $this->archived; } /** * @param boolean $archived * @return Bill */ public function setArchived($archived) { $this->archived = (boolean) $archived; return $this; } } php-client/src/Bitpay/KeyInterface.php000075500000000602152503640360013715 0ustar00value; } /** * @param PublicKey * @return SinKey */ public function setPublicKey(PublicKey $publicKey) { $this->publicKey = $publicKey; return $this; } /** * Generates a Service Identification Number (SIN), see: * https://en.bitcoin.it/wiki/Identity_protocol_v1 * * @return SinKey * @throws \Exception */ public function generate() { if (is_null($this->publicKey)) { throw new \Exception('Public Key has not been set'); } $compressedValue = $this->publicKey; if (empty($compressedValue)) { throw new \Exception('The Public Key needs to be generated.'); } $step1 = Util::sha256(Util::binConv($compressedValue), true); $step2 = Util::ripe160($step1); $step3 = sprintf( '%s%s%s', self::SIN_VERSION, self::SIN_TYPE, $step2 ); $step4 = Util::twoSha256(Util::binConv($step3), true); $step5 = substr(bin2hex($step4), 0, 8); $step6 = $step3 . $step5; $this->value = Base58::encode($step6); return $this; } /** * Checks to make sure that this SIN is a valid object. * * @return boolean */ public function isValid() { return (!is_null($this->value) && (substr($this->value, 0, 1) == 'T')); } } php-client/src/Bitpay/PaymentUrlSet.php000075500000001673152503640360014131 0ustar00paymentUrls = $paymentUrls; } /** * Return the account parameter given by Bitpay. * * @return string */ public function getUrl($urlType) { if (array_key_exists($urlType, $this->paymentUrls)) { return $this->paymentUrls[$urlType]; } return null; } /** * Return the account parameter given by Bitpay. * * @return PaymentUrlInterface */ public function setUrls(array $paymentUrls) { $this->paymentUrls = $paymentUrls; return $this; } } php-client/src/Bitpay/Application.php000075500000002226152503640360013613 0ustar00users = array(); $this->orgs = array(); } /** * @inheritdoc */ public function getUsers() { return $this->users; } /** * @inheritdoc */ public function getOrgs() { return $this->orgs; } /** * Add user to stack * * @param User $user * @return Application */ public function addUser(User $user) { if (!empty($user)) { $this->users[] = $user; } return $this; } /** * Add org to stack * * @param Org $org * @return Application */ public function addOrg(Org $org) { if (!empty($org)) { $this->orgs[] = $org; } return $this; } } php-client/src/Bitpay/Config/Configuration.php000075500000010274152503640360015366 0ustar00root('bitpay'); $rootNode ->children() ->scalarNode('public_key') ->info('Public Key Filename') ->defaultValue($this->getPubKeyFilename()) ->end() ->scalarNode('private_key') ->info('Private Key Filename') ->defaultValue($this->getPriKeyFilename()) ->end() ->scalarNode('sin_key') ->info('SIN Filename') ->defaultValue($this->getSinFilename()) ->end() ->enumNode('network') ->values($this->networks) ->info('Network') ->defaultValue($this->networks[0]) ->end() ->enumNode('adapter') ->values($this->adapters) ->info('Client Adapter') ->defaultValue($this->adapters[0]) ->end() ->append($this->addKeyStorageNode()) ->scalarNode('key_storage_password') ->info('Used to encrypt and decrypt keys when saving to filesystem') ->defaultNull() ->end() ->end(); return $treeBuilder; } /** * Adds the key_storage node with validation rules. * key_storage MUST: * * implement Bitpay\Storage\StorageInterface * * be a class that can be loaded * * @return \Symfony\Component\Config\Definition\Builder\NodeDefinition * @throws \Exception */ protected function addKeyStorageNode() { $builder = new TreeBuilder(); $node = $builder->root('key_storage', 'scalar'); $node ->info('Class that is used to store your keys') ->defaultValue($this->defstorage) ->validate() ->always() ->then(function ($value) { if (!class_exists($value)) { throw new \Exception( sprintf( 'Could not find class "%s".', $value ) ); } // requires PHP >= 5.3.7 if (is_subclass_of($value, 'Bitpay\Storage\StorageInterface') === false) { throw new \Exception('[ERROR] In Configuration::addKeyStorageNode(): "' . $value . '" does not implement "Bitpay\Storage\StorageInterface".'); } return $value; }) ->end(); return $node; } /** * @return string */ private function getPubKeyFilename() { return getenv('HOME') . $this->pubfilename; } /** * @return string */ private function getPriKeyFilename() { return getenv('HOME') . $this->prifilename; } /** * @return string */ private function getSinFilename() { return getenv('HOME') . $this->sinfilename; } } php-client/src/Bitpay/PayoutInstruction.php000075500000007354152503640360015102 0ustar00transactions = array(); } /** * @inheritdoc */ public function getId() { return $this->id; } /** * Set the Bitpay ID for this payout instruction * * @param $id * @return $this */ public function setId($id) { if (!empty($id)) { $this->id = trim($id); } return $this; } /** * @inheritdoc */ public function getLabel() { return $this->label; } /** * Set the employers label for this instruction. * @param $label * @return $this */ public function setLabel($label) { if (!empty($label)) { $this->label = trim($label); } return $this; } /** * @inheritdoc */ public function getAddress() { return $this->address; } /** * Set the bitcoin address for this instruction. * @param $address * @return $this */ public function setAddress($address) { if (!empty($address)) { $this->address = trim($address); } return $this; } /** * @inheritdoc */ public function getAmount() { return $this->amount; } /** * Set the amount for this instruction. * @param $amount * @return $this */ public function setAmount($amount) { if (!empty($amount)) { $this->amount = $amount; } return $this; } /** * @inheritdoc */ public function getBtc() { return $this->btc; } /** * Set BTC array (available once rates are set) * @param $btc * @return $this */ public function setBtc($btc) { if (!empty($btc) && is_array($btc)) { $this->btc = $btc; } return $this; } /** * @inheritdoc */ public function getStatus() { return $this->status; } /** * Set the status for this instruction * @param $status * @return $this */ public function setStatus($status) { if (!empty($status) && ctype_print($status)) { $this->status = trim($status); } return $this; } /** * @inheritdoc */ public function getTransactions() { return $this->transactions; } /** * Add payout transaction to the * @param PayoutTransactionInterface $transaction * @return $this */ public function addTransaction(PayoutTransactionInterface $transaction) { if (!empty($transaction)) { $this->transactions[] = $transaction; } return $this; } } php-client/src/Bitpay/Currency.php000075500000014347152503640360013151 0ustar00setCode($code); } $this->payoutEnabled = false; $this->payoutFields = array(); } /** * @inheritdoc */ public function getCode() { return $this->code; } /** * This will change the $code to all uppercase * * @param string $code The Currency Code to use, ie USD * @throws Exception Throws an exception if the Currency Code is not supported * @return CurrencyInterface */ public function setCode($code) { if (null !== $code && !in_array(strtoupper($code), self::$availableCurrencies)) { throw new \Bitpay\Client\ArgumentException( sprintf('The currency code "%s" is not supported.', $code) ); } $this->code = strtoupper($code); return $this; } /** * @inheritdoc */ public function getSymbol() { return $this->symbol; } /** * @param string $symbol * * @return CurrencyInterface */ public function setSymbol($symbol) { if (!empty($symbol) && ctype_print($symbol)) { $this->symbol = trim($symbol); } return $this; } /** * @inheritdoc */ public function getPrecision() { return $this->precision; } /** * @param integer $precision * * @return CurrencyInterface */ public function setPrecision($precision) { if (!empty($precision) && ctype_digit(strval($precision))) { $this->precision = (int) $precision; } return $this; } /** * @inheritdoc */ public function getExchangePctFee() { return $this->exchangePercentageFee; } /** * @param string $fee * * @return CurrencyInterface */ public function setExchangePctFee($fee) { if (!empty($fee) && ctype_print($fee)) { $this->exchangePercentageFee = trim($fee); } return $this; } /** * @inheritdoc */ public function isPayoutEnabled() { return $this->payoutEnabled; } /** * @param boolean $enabled * * @return CurrencyInterface */ public function setPayoutEnabled($enabled) { $this->payoutEnabled = (boolean) $enabled; return $this; } /** * @inheritdoc */ public function getName() { return $this->name; } /** * @param string $name * * @return CurrencyInterface */ public function setName($name) { if (!empty($name) && ctype_print($name)) { $this->name = trim($name); } return $this; } /** * @inheritdoc */ public function getPluralName() { return $this->pluralName; } /** * @param string $pluralName * * @return CurrencyInterface */ public function setPluralName($pluralName) { if (!empty($pluralName) && ctype_print($pluralName)) { $this->pluralName = trim($pluralName); } return $this; } /** * @inheritdoc */ public function getAlts() { return $this->alts; } /** * @param array $alts * * @return CurrencyInterface */ public function setAlts($alts) { $this->alts = $alts; return $this; } /** * @inheritdoc */ public function getPayoutFields() { return $this->payoutFields; } /** * @param array $payoutFields * * @return CurrencyInterface */ public function setPayoutFields(array $payoutFields) { $this->payoutFields = $payoutFields; return $this; } } php-client/src/Bitpay/Key.php000075500000003460152503640360012101 0ustar00id = $id; } /** * @return string */ public function getId() { return $this->id; } /** * Returns a new instance of self. * * @param string $id * @return \Bitpay\KeyInterface */ public static function create($id = null) { $class = get_called_class(); return new $class($id); } /** * @return string */ public function getHex() { return $this->hex; } /** * @return string */ public function getDec() { return $this->dec; } /** * @inheritdoc */ public function serialize() { return serialize( array( $this->id, $this->x, $this->y, $this->hex, $this->dec, ) ); } /** * @inheritdoc */ public function unserialize($data) { list( $this->id, $this->x, $this->y, $this->hex, $this->dec ) = unserialize($data); } /** * @return boolean */ public function isGenerated() { return (!empty($this->hex)); } } php-client/src/Bitpay/PointInterface.php000075500000001041152503640360014254 0ustar00id; } /** * Set the batch ID as assigned from bitpay. * * @param $id * @return $this */ public function setId($id) { if (!empty($id) && ctype_print($id)) { $this->id = trim($id); } return $this; } /** * @inheritdoc */ public function getAccountId() { return $this->account_id; } /** * Set Account Id - Bitpays account ID for the payout. * * @param $id * @return $this */ public function setAccountId($id) { if (!empty($id) && ctype_print($id)) { $this->account_id = $id; } return $this; } /** * @inheritdoc */ public function getAmount() { return $this->amount; } /** * Sets the amount for this payout. * @param $amount * @return $this */ public function setAmount($amount) { if (!empty($amount)) { $this->amount = $amount; } return $this; } /** * @interitdoc */ public function getCurrency() { return $this->currency; } /** * Set Currency * @param CurrencyInterface $currency * @return $this */ public function setCurrency(CurrencyInterface $currency) { if (!empty($currency)) { $this->currency = $currency; } return $this; } /** * @inheritdoc */ public function getEffectiveDate() { return $this->effectiveDate; } /** * Set Effective date - date payout should be given to employees. * @param $effectiveDate * @return $this */ public function setEffectiveDate($effectiveDate) { if (!empty($effectiveDate)) { $this->effectiveDate = $effectiveDate; } return $this; } /** * Get rate assigned to payout at effectiveDate */ public function getRate() { return $this->rate; } /** * Set the rate in bitcoin for the payouts of this transaction. * @param $rate * @return $this */ public function setRate($rate) { if (!empty($rate)) { $this->rate = $rate; } return $this; } /** * @inheritdoc */ public function getBtcAmount() { return $this->btc; } /** * Set the Bitcoin amount for this payout, once set by Bitpay. * @param $amount * @return $this */ public function setBtcAmount($amount) { if (!empty($amount)) { $this->btc = $amount; } return $this; } /** * @inheritdoc */ public function getRequestDate() { return $this->requestDate; } /** * Set */ public function setRequestDate($requestDate) { if (!empty($requestDate)) { $this->requestDate = $requestDate; } return $this; } /** * @inheritdoc */ public function getInstructions() { return $this->instructions; } /** * Add Instruction of PayoutInstructionInterface type * Increases $this->amount by value. * * @param PayoutInstructionInterface $instruction * @return $this */ public function addInstruction(PayoutInstructionInterface $instruction) { if (!empty($instruction)) { $this->instructions[] = $instruction; } return $this; } /** * Update Instruction - Supply an index of the instruction to update, * plus the function and single argument, to do something to an instruction. * * @param $index * @param $function * @param $argument * @return $this */ public function updateInstruction($index, $function, $argument) { if (!empty($argument) && ctype_print($argument)) { $this->instructions[$index]->$function($argument); } return $this; } /** * @inheritdoc */ public function getStatus() { return $this->status; } /** * Sets the status for the current payout request * @param $status * @return $this */ public function setStatus($status) { if (!empty($status) && ctype_print($status)) { $this->status = trim($status); } return $this; } /** * @inheritdoc */ public function getToken() { return $this->token; } /** * Set the token to authorize this request. * @param TokenInterface $token * @return $this */ public function setToken(TokenInterface $token) { if (!empty($token)) { $this->token = $token; } return $this; } /** * @inheritdoc */ public function getResponseToken() { return $this->responseToken; } /** * Set Response Token - returned by Bitpay when payout request is created * * @param $responseToken * @return $this */ public function setResponseToken($responseToken) { if (!empty($responseToken)) { $this->responseToken = trim($responseToken); } return $this; } /** * @inheritdoc */ public function getPricingMethod() { return $this->pricingMethod; } /** * Set the pricing method for this payout request * @param $pricingMethod * @return $this */ public function setPricingMethod($pricingMethod) { if (!empty($pricingMethod) && ctype_print($pricingMethod)) { $this->pricingMethod = trim($pricingMethod); } return $this; } /** * @inheritdoc */ public function getReference() { return $this->reference; } /** * Set the payroll providers reference for this payout * * @param $reference * @return $this */ public function setReference($reference) { if (!empty($reference) && ctype_print($reference)) { $this->reference = trim($reference); } return $this; } /** * @inheritdoc */ public function getNotificationEmail() { return $this->notificationEmail; } /** * Set an email address where updates to payout status should be sent. * * @param $notificationEmail * @return $this */ public function setNotificationEmail($notificationEmail) { if (!empty($notificationEmail) && ctype_print($notificationEmail)) { $this->notificationEmail = trim($notificationEmail); } return $this; } /** * @inheritdoc */ public function getNotificationUrl() { return $this->notificationUrl; } /** * Set a notification url - where updated Payout objects will be sent * * @param $notificationUrl * @return $this */ public function setNotificationUrl($notificationUrl) { if (!empty($notificationUrl) && ctype_print($notificationUrl)) { $this->notificationUrl = trim($notificationUrl); } return $this; } } php-client/src/Bitpay/Invoice.php000075500000033644152503640360012754 0ustar00currency = $currency; $this->transactionSpeed = $transactionSpeed; $this->fullNotifications = $fullNotifications; $this->item = $item; $this->orderId = $orderId; $this->posData = $posData; } /** * @inheritdoc */ public function getPrice() { if (is_a($this->item, '\Bitpay\Item')) { return $this->getItem()->getPrice(); } else { return 0.000000; } } /** * @param float $price * @return Invoice */ public function setPrice($price) { if (is_numeric($price)) { $this->getItem()->setPrice(floatval($price)); } return $this; } /** * @inheritdoc */ public function getCurrency() { if ($this->currency === null) { $this->currency = new Currency('BTC'); } return $this->currency; } /** * @param CurrencyInterface $currency * @return Invoice */ public function setCurrency(CurrencyInterface $currency) { if (is_a($currency, '\Bitpay\Currency')) { $this->currency = $currency; } return $this; } /** * @inheritdoc */ public function getItem() { if (null === $this->item) { $this->item = new Item(); } return $this->item; } /** * @param ItemInterface $item * @return Invoice */ public function setItem(ItemInterface $item) { if (is_a($item, '\Bitpay\Item')) { $this->item = $item; } return $this; } /** * @inheritdoc */ public function getBuyer() { if ($this->buyer === null) { $this->buyer = new Buyer(); } return $this->buyer; } /** * @param BuyerInterface $buyer * @return Invoice */ public function setBuyer(BuyerInterface $buyer) { if (is_a($buyer, '\Bitpay\Buyer')) { $this->buyer = $buyer; } return $this; } /** * @inheritdoc */ public function getTransactionSpeed() { return $this->transactionSpeed; } /** * @param string $transactionSpeed * @return Invoice */ public function setTransactionSpeed($transactionSpeed) { switch (strtolower(trim($transactionSpeed))) { case 'high': $this->transactionSpeed = self::TRANSACTION_SPEED_HIGH; break; case 'medium': $this->transactionSpeed = self::TRANSACTION_SPEED_MEDIUM; break; case 'low': default: $this->transactionSpeed = self::TRANSACTION_SPEED_LOW; } return $this; } /** * @inheritdoc */ public function getNotificationEmail() { return $this->notificationEmail; } /** * @param string $notificationEmail * @return Invoice */ public function setNotificationEmail($notificationEmail) { if (filter_var($notificationEmail, FILTER_VALIDATE_EMAIL)) { $this->notificationEmail = trim($notificationEmail); } return $this; } /** * @inheritdoc */ public function getNotificationUrl() { return $this->notificationUrl; } /** * @param string $notificationUrl * @return Invoice */ public function setNotificationUrl($notificationUrl) { if (preg_match("/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i", $notificationUrl)) { $this->notificationUrl = trim($notificationUrl); } return $this; } /** * @inheritdoc */ public function getRedirectUrl() { return $this->redirectUrl; } /** * @param string $redirectUrl * @return Invoice */ public function setRedirectUrl($redirectUrl) { if (preg_match("/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i", $redirectUrl)) { $this->redirectUrl = trim($redirectUrl); } return $this; } /** * @inheritdoc */ public function getPosData() { return $this->posData; } /** * @param string $posData * @return Invoice */ public function setPosData($posData) { if (is_string($posData)) { $this->posData = $posData; } return $this; } /** * @inheritdoc */ public function getStatus() { return $this->status; } /** * @param string $status * @return Invoice */ public function setStatus($status) { if (is_string($status)) { $this->status = trim($status); } return $this; } /** * @inheritdoc */ public function isFullNotifications() { return $this->fullNotifications; } public function setFullNotifications($notifications) { $this->fullNotifications = (boolean) $notifications; return $this; } /** * @inheritdoc */ public function getId() { return $this->id; } /** * @param string $id * @return Invoice */ public function setId($id) { if (is_string($id)) { $this->id = trim($id); } return $this; } /** * @inheritdoc */ public function getUrl() { return $this->url; } /** * @param string $url * @return Invoice */ public function setUrl($url) { if (preg_match("/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i", $url)) { $this->url = trim($url); } return $this; } /** * @inheritdoc */ public function getBtcPrice() { return $this->btcPrice; } /** * @param float $btcPrice * @return Invoice */ public function setBtcPrice($btcPrice) { if (is_numeric($btcPrice)) { $this->btcPrice = floatval($btcPrice); } return $this; } /** * @inheritdoc */ public function getInvoiceTime() { return $this->invoiceTime; } /** * @param \DateTime $invoiceTime * @return Invoice */ public function setInvoiceTime($invoiceTime) { if (is_a($invoiceTime, 'DateTime')) { $this->invoiceTime = $invoiceTime; } else if (is_numeric($invoiceTime)) { $invoiceDateTime = new \DateTime(); $invoiceDateTime->setTimestamp($invoiceTime); $this->invoiceTime = $invoiceDateTime; } return $this; } /** * @inheritdoc */ public function getExpirationTime() { return $this->expirationTime; } /** * @param \DateTime $expirationTime * return Invoice */ public function setExpirationTime($expirationTime) { if (is_a($expirationTime, 'DateTime')) { $this->expirationTime = $expirationTime; } else if (is_numeric($expirationTime)) { $expirationDateTime = new \DateTime(); $expirationDateTime->setTimestamp($expirationTime); $this->expirationTime = $expirationDateTime; } return $this; } /** * @inheritdoc */ public function getCurrentTime() { return $this->currentTime; } /** * @param \DateTime $currentTime * @return Invoice */ public function setCurrentTime($currentTime) { if (is_a($currentTime, 'DateTime')) { $this->currentTime = $currentTime; } else if (is_numeric($currentTime)) { $currentDateTime = new \DateTime(); $currentDateTime->setTimestamp($currentTime); $this->currentTime = $currentDateTime; } return $this; } /** * @inheritdoc */ public function getOrderId() { return $this->orderId; } /** * @param string $orderId * @return Invoice */ public function setOrderId($orderId) { if (is_string($orderId)) { $this->orderId = trim($orderId); } return $this; } /** * @inheritdoc */ public function getItemDesc() { return $this->getItem()->getDescription(); } /** * @inheritdoc */ public function getItemCode() { return $this->getItem()->getCode(); } /** * @inheritdoc */ public function isPhysical() { return $this->getItem()->isPhysical(); } /** * @inheritdoc */ public function getBuyerName() { $firstName = $this->getBuyer()->getFirstName(); $lastName = $this->getBuyer()->getLastName(); return trim($firstName . ' ' . $lastName); } /** * @inheritdoc */ public function getBuyerAddress1() { $address = $this->getBuyer()->getAddress(); return $address[0]; } /** * @inheritdoc */ public function getBuyerAddress2() { $address = $this->getBuyer()->getAddress(); return $address[1]; } /** * @inheritdoc */ public function getBuyerCity() { return $this->getBuyer()->getCity(); } /** * @inheritdoc */ public function getBuyerState() { return $this->getBuyer()->getState(); } /** * @inheritdoc */ public function getBuyerZip() { return $this->getBuyer()->getZip(); } /** * @inheritdoc */ public function getBuyerCountry() { return $this->getBuyer()->getCountry(); } /** * @inheritdoc */ public function getBuyerEmail() { return $this->getBuyer()->getEmail(); } /** * @inheritdoc */ public function getBuyerPhone() { return $this->getBuyer()->getEmail(); } /** * @inheritdoc */ public function getExceptionStatus() { return $this->exceptionStatus; } /** * @param * @return Invoice */ public function setExceptionStatus($exceptionStatus) { $this->exceptionStatus = $exceptionStatus; return $this; } /** * @param void * @return */ public function getBtcPaid() { return $this->btcPaid; } /** * @param * @return Invoice */ public function setBtcPaid($btcPaid) { if (is_numeric($btcPaid)) { $this->btcPaid = $btcPaid; } return $this; } /** * @param void * @return Invoice */ public function getRate() { return $this->rate; } /** * @param * @return */ public function setRate($rate) { if (is_numeric($rate)) { $this->rate = floatval($rate); } return $this; } /** * @return TokenInterface */ public function getToken() { return $this->token; } /** * @param TokenInterface $token * @return Invoice */ public function setToken(TokenInterface $token) { if (is_a($token, '\Bitpay\Token')) { $this->token = $token; } return $this; } /** * @return PaymentUrlInterface */ public function getPaymentUrls() { if ($this->paymentUrls === null) { $this->paymentUrls = new PaymentUrlSet(); } return $this->paymentUrls; } /** * @param PaymentUrlInterface $paymentUrls * @return Invoice */ public function setPaymentUrls(PaymentUrlInterface $paymentUrls) { $this->paymentUrls = $paymentUrls; return $this; } /** * @param string $paymentUrlType * @return string */ public function getPaymentUrl($paymentUrlType) { return $this->getPaymentUrls()->getUrl($paymentUrlType); } } php-client/src/Bitpay/PrivateKey.php000075500000023476152503640360013445 0ustar00hex; } /** * @return PublicKey */ public function getPublicKey() { if (null === $this->publicKey) { $this->publicKey = new PublicKey(); $this->publicKey->setPrivateKey($this); $this->publicKey->generate(); } return $this->publicKey; } /** * Generates an EC private key * * @return \Bitpay\PrivateKey */ public function generate() { if (!empty($this->hex)) { return $this; } do { $privateKey = \Bitpay\Util\SecureRandom::generateRandom(32); $this->hex = strtolower(bin2hex($privateKey)); } while (Math::cmp('0x'.$this->hex, '1') <= 0 || Math::cmp('0x' . $this->hex, '0x' . Secp256k1::N) >= 0); $this->dec = Util::decodeHex($this->hex); return $this; } /** * Checks to see if the private key value is not empty and * the hex form only contains hexits and the decimal form * only contains devimal digits. * * @return boolean */ public function isValid() { return ($this->hasValidDec() && $this->hasValidHex()); } /** * @return boolean */ public function hasValidHex() { return (!empty($this->hex) || ctype_xdigit($this->hex)); } /** * @return boolean */ public function hasValidDec() { return (!empty($this->dec) || ctype_digit($this->dec)); } /** * Creates an ECDSA signature of $data. * * @param string * @return string * @throws \Exception */ public function sign($data) { if (!ctype_xdigit($this->hex)) { throw new \Exception('The private key must be in hex format.'); } if (empty($data)) { throw new \Exception('You did not provide any data to sign.'); } $e = Util::decodeHex(hash('sha256', $data)); do { if (substr(strtolower($this->hex), 0, 2) != '0x') { $d = '0x' . $this->hex; } else { $d = $this->hex; } $k = SecureRandom::generateRandom(32); $k_hex = '0x' . strtolower(bin2hex($k)); $n_hex = '0x' . Secp256k1::N; $Gx = '0x' . substr(Secp256k1::G, 2, 64); $Gy = '0x' . substr(Secp256k1::G, 66, 64); $P = new Point($Gx, $Gy); // Calculate a new curve point from Q=k*G (x1,y1) $R = Util::doubleAndAdd($k_hex, $P); $Rx_hex = Util::encodeHex($R->getX()); $Rx_hex = str_pad($Rx_hex, 64, '0', STR_PAD_LEFT); // r = x1 mod n $r = Math::mod('0x' . $Rx_hex, $n_hex); // s = k^-1 * (e+d*r) mod n $edr = Math::add($e, Math::mul($d, $r)); $invk = Math::invertm($k_hex, $n_hex); $kedr = Math::mul($invk, $edr); $s = Math::mod($kedr, $n_hex); // The signature is the pair (r,s) $signature = array( 'r' => Util::encodeHex($r), 's' => Util::encodeHex($s), ); $signature['r'] = str_pad($signature['r'], 64, '0', STR_PAD_LEFT); $signature['s'] = str_pad($signature['s'], 64, '0', STR_PAD_LEFT); } while (Math::cmp($r, '0') <= 0 || Math::cmp($s, '0') <= 0); $sig = array( 'sig_rs' => $signature, 'sig_hex' => self::serializeSig($signature['r'], $signature['s']), ); return $sig['sig_hex']['seq']; } /** * ASN.1 DER encodes the signature based on the form: * 0x30 + size(all) + 0x02 + size(r) + r + 0x02 + size(s) + s * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf * * @param string * @param string * @return string */ public static function serializeSig($r, $s) { $dec = ''; $byte = ''; $seq = ''; $digits = array(); $retval = array(); for ($x = 0; $x < 256; $x++) { $digits[$x] = chr($x); } $dec = Util::decodeHex($r); while (Math::cmp($dec, '0') > 0) { $dv = Math::div($dec, '256'); $rem = Math::mod($dec, '256'); $dec = $dv; $byte = $byte . $digits[$rem]; } $byte = strrev($byte); // msb check if (Math::cmp('0x' . bin2hex($byte[0]), '0x80') >= 0) { $byte = chr(0x00) . $byte; } $retval['bin_r'] = bin2hex($byte); $seq = chr(0x02) . chr(strlen($byte)) . $byte; $dec = Util::decodeHex($s); $byte = ''; while (Math::cmp($dec, '0') > 0) { $dv = Math::div($dec, '256'); $rem = Math::mod($dec, '256'); $dec = $dv; $byte = $byte . $digits[$rem]; } $byte = strrev($byte); // msb check if (Math::cmp('0x' . bin2hex($byte[0]), '0x80') >= 0) { $byte = chr(0x00) . $byte; } $retval['bin_s'] = bin2hex($byte); $seq = $seq . chr(0x02) . chr(strlen($byte)) . $byte; $seq = chr(0x30) . chr(strlen($seq)) . $seq; $retval['seq'] = bin2hex($seq); return $retval; } /** * Decodes PEM data to retrieve the keypair. * * @param string $pem_data The data to decode. * @return array The keypair info. * @throws \Exception */ public function pemDecode($pem_data) { $beg_ec_text = '-----BEGIN EC PRIVATE KEY-----'; $end_ec_text = '-----END EC PRIVATE KEY-----'; $decoded = ''; $ecpemstruct = array(); $pem_data = str_ireplace($beg_ec_text, '', $pem_data); $pem_data = str_ireplace($end_ec_text, '', $pem_data); $pem_data = str_ireplace("\r", '', trim($pem_data)); $pem_data = str_ireplace("\n", '', trim($pem_data)); $pem_data = str_ireplace(' ', '', trim($pem_data)); $decoded = bin2hex(base64_decode($pem_data)); if (strlen($decoded) < 230) { throw new \Exception('Invalid or corrupt secp256k1 key provided. Cannot decode the supplied PEM data.'); } $ecpemstruct = array( 'oct_sec_val' => substr($decoded, 14, 64), 'obj_id_val' => substr($decoded, 86, 10), 'bit_str_val' => substr($decoded, 106), ); if ($ecpemstruct['obj_id_val'] != '2b8104000a') { throw new \Exception('Invalid or corrupt secp256k1 key provided. Cannot decode the supplied PEM data.'); } $private_key = $ecpemstruct['oct_sec_val']; $public_key = $ecpemstruct['bit_str_val']; if (strlen($private_key) < 64 || strlen($public_key) < 128) { throw new \Exception('Invalid or corrupt secp256k1 key provided. Cannot decode the supplied PEM data.'); } $this->pemDecoded = array('private_key' => $private_key, 'public_key' => $public_key); return $this->pemDecoded; } /** * Encodes keypair data to PEM format. * * @param array $keypair The keypair info. * @return string The data to decode. * @throws \Exception */ public function pemEncode($keypair) { if (is_array($keypair) && (strlen($keypair[0]) < 64 || strlen($keypair[1]) < 128)) { throw new \Exception('Invalid or corrupt secp256k1 keypair provided. Cannot decode the supplied PEM data.'); } $dec = ''; $byte = ''; $beg_ec_text = ''; $end_ec_text = ''; $ecpemstruct = array(); $digits = array(); for ($x = 0; $x < 256; $x++) { $digits[$x] = chr($x); } $ecpemstruct = array( 'sequence_beg' => '30', 'total_len' => '74', 'int_sec_beg' => '02', 'int_sec_len' => '01', 'int_sec_val' => '01', 'oct_sec_beg' => '04', 'oct_sec_len' => '20', 'oct_sec_val' => $keypair[0], 'a0_ele_beg' => 'a0', 'a0_ele_len' => '07', 'obj_id_beg' => '06', 'obj_id_len' => '05', 'obj_id_val' => '2b8104000a', 'a1_ele_beg' => 'a1', 'a1_ele_len' => '44', 'bit_str_beg' => '03', 'bit_str_len' => '42', 'bit_str_val' => '00' . $keypair[1], ); $beg_ec_text = '-----BEGIN EC PRIVATE KEY-----'; $end_ec_text = '-----END EC PRIVATE KEY-----'; $dec = trim(implode($ecpemstruct)); if (strlen($dec) < 230) { throw new \Exception('Invalid or corrupt secp256k1 keypair provided. Cannot encode the supplied data.'); } $dec = Util::decodeHex('0x' . $dec); while (Math::cmp($dec, '0') > 0) { $dv = Math::div($dec, '256'); $rem = Math::mod($dec, '256'); $dec = $dv; $byte = $byte . $digits[$rem]; } $byte = $beg_ec_text . "\r\n" . chunk_split(base64_encode(strrev($byte)), 64) . $end_ec_text; $this->pemEncoded = $byte; return $byte; } } php-client/src/Bitpay/Network/NetworkInterface.php000075500000001435152503640360016254 0ustar00host_url = $url; $this->host_port = $port; $this->isPortRequiredInUrl = $isPortRequiredInUrl; } public function getName() { return 'Custom Network'; } public function getAddressVersion() { return 0x00; } public function getApiHost() { return $this->host_url; } public function getApiPort() { return $this->host_port; } } php-client/src/Bitpay/Network/Livenet.php000075500000001023152503640360014401 0ustar00network = $network; } } php-client/src/Bitpay/Network/Testnet.php000075500000001047152503640360014427 0ustar00container = $container; if (is_null($container)) { $this->initializeContainer($config); } } /** * Initialize the container * * @param array|string $config */ protected function initializeContainer($config) { $this->container = $this->buildContainer($config); $this->container->compile(); } /** * Build the container of services and parameters. * * @param array|string $config * @return ContainerBuilder */ protected function buildContainer($config) { $container = new ContainerBuilder(new ParameterBag($this->getParameters())); $this->prepareContainer($container); $this->getContainerLoader($container)->load($config); return $container; } /** * @return array */ protected function getParameters() { return array( 'bitpay.root_dir' => realpath(__DIR__ . '/..'), ); } /** * @param ContainerBuilder $container */ private function prepareContainer(ContainerBuilder $container) { foreach ($this->getDefaultExtensions() as $ext) { $container->registerExtension($ext); $container->loadFromExtension($ext->getAlias()); } } /** * @param ContainerBuilder $container * @return DelegatingLoader */ private function getContainerLoader(ContainerBuilder $container) { $locator = new FileLocator(); $resolver = new LoaderResolver( array( new ArrayLoader($container), new YamlFileLoader($container, $locator), ) ); return new DelegatingLoader($resolver); } /** * Returns an array of the default extensions. * * @return BitpayExtension[] */ private function getDefaultExtensions() { return array( new BitpayExtension(), ); } /** * @return ContainerBuilder */ public function getContainer() { return $this->container; } /** * @return object|null */ public function get($service) { return $this->container->get($service); } } php-client/src/Bitpay/UserInterface.php000075500000001622152503640360014106 0ustar00physical = false; } /** * @inheritdoc */ public function getCode() { return $this->code; } /** * @param string $code * @return ItemInterface */ public function setCode($code) { $this->code = $code; return $this; } /** * @inheritdoc */ public function getDescription() { return $this->description; } /** * @param string $description * @return ItemInterface */ public function setDescription($description) { $this->description = $description; return $this; } /** * @inheritdoc */ public function getPrice() { return $this->price; } /** * @param mixed $price A float, integer, or en_US formatted numeric string * @return Item */ public function setPrice($price) { if (is_string($price)) { $this->checkPriceFormat($price); } $this->price = (float)$price; return $this; } /** * @inheritdoc */ public function getQuantity() { return $this->quantity; } /** * @param integer $quantity * @return Item */ public function setQuantity($quantity) { $this->quantity = $quantity; return $this; } /** * @inheritdoc */ public function isPhysical() { return $this->physical; } /** * @param boolean $physical * @return Item */ public function setPhysical($physical) { $this->physical = (boolean)$physical; return $this; } /** * Checks the new price to include BTC * values with more than 6 decimals. * * @param string $price The price value to check * @throws \Exception */ protected function checkPriceFormat($price) { if (preg_match('/^[0-9]+?[\.,][0-9]{1,6}?$/', $price) !== 1) { throw new \Bitpay\Client\ArgumentException('[ERROR] In Item::checkPriceFormat(): Price value must be formatted as a float.'); } } } php-client/src/Bitpay/PayoutInterface.php000075500000010641152503640360014452 0ustar00container = $container; } public function load($resource, $type = null) { // validation foreach (array_keys($resource) as $namespace) { if (in_array($namespace, array('imports', 'paramters', 'services'))) { continue; } if (!$this->container->hasExtension($namespace)) { $extensionNamespaces = array_filter( array_map( function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions() ) ); throw new InvalidArgumentException(sprintf( 'There is no extension able to load the configuration for "%s". Looked for namespace "%s", found %s', $namespace, $namespace, $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none' )); } } // Set Paramters if (isset($resource['parameters'])) { foreach ($resource['parameters'] as $key => $value) { $this->container->setParameter($key, $value); } } // extensions foreach ($resource as $namespace => $values) { if (in_array($namespace, array('imports', 'parameters', 'services'))) { continue; } if (!is_array($values)) { $values = array(); } $this->container->loadFromExtension($namespace, $values); } } public function supports($resource, $type = null) { return is_array($resource); } } php-client/src/Bitpay/DependencyInjection/BitpayExtension.php000075500000003373152503640360020422 0ustar00processConfiguration(new Configuration(), $configs); foreach (array_keys($config) as $key) { $container->setParameter('bitpay.'.$key, $config[$key]); } $loader = new XmlFileLoader($container, new FileLocator(__DIR__)); $loader->load('services.xml'); $container->setParameter('network.class', 'Bitpay\Network\\'.ContainerBuilder::camelize($config['network'])); $container->setParameter( 'adapter.class', 'Bitpay\Client\Adapter\\'.ContainerBuilder::camelize($config['adapter']).'Adapter' ); $container->setParameter('key_storage.class', $config['key_storage']); } /** * @codeCoverageIgnore */ public function getAlias() { return 'bitpay'; } /** * @codeCoverageIgnore */ public function getNamespace() { return 'http://example.org/schema/dic/bitpay'; } /** * @codeCoverageIgnore */ public function getXsdValidationBasePath() { return false; } } php-client/src/Bitpay/DependencyInjection/services.xml000075500000003512152503640360017124 0ustar00 Bitpay\Network\Livenet Bitpay\Client\Adapter\CurlAdapter Bitpay\KeyManager Bitpay\Storage\FilesystemStorage %bitpay.key_storage_password% %bitpay.public_key% %bitpay.private_key% php-client/src/Bitpay/Client/RequestInterface.php000075500000003117152503640360016037 0ustar00 $value array of http headers * * @return array */ public function getHeaders(); } php-client/src/Bitpay/Client/ConnectionException.php000075500000000366152503640360016547 0ustar00headers = array( 'Content-Type' => 'application/json', 'X-BitPay-Plugin-Info' => null, ); $this->port = 443; // Default method is POST $this->method = self::METHOD_POST; } /** * Converts this request into a standard HTTP/1.1 message to be sent over * the wire. * * @return string */ public function __toString() { $request = sprintf("%s %s HTTP/1.1\r\n", $this->getMethod(), $this->getUriWithPort()); $request .= $this->getHeadersAsString(); $request .= $this->getBody(); return trim($request); } /** * @inheritdoc */ public function isMethod($method) { return (strtoupper($method) == strtoupper($this->method)); } /** * @inheritdoc */ public function getPort() { return $this->port; } /** * @inheritdoc */ public function setPort($port) { $this->port = $port; } /** * @inheritdoc */ public function getMethod() { return $this->method; } /** * Set the method of the request, for known methods see the * RequestInterface. * * @param string $method */ public function setMethod($method) { $this->method = $method; } /** * @inheritdoc */ public function getSchema() { return 'https'; } /** * @inheritdoc */ public function getUri() { return sprintf( '%s://%s/%s', $this->getSchema(), $this->getHost(), $this->getPath() ); } /** * @inheritdoc */ public function getUriWithPort() { return sprintf( '%s://%s:%s/%s', $this->getSchema(), $this->getHost(), $this->getPort(), $this->getPath() ); } /** * @inheritdoc */ public function getHost() { return $this->host; } /** * Sets the host for the request. * * @param string $host * @return Request */ public function setHost($host) { $this->host = $host; return $this; } /** * @inheritdoc */ public function getHeaders() { // remove invalid headers $headers = $this->headers; foreach ($headers as $header => $value) { if (empty($header) || empty($value)) { unset($headers[$header]); } } return $headers; } /** * @return array */ public function getHeaderFields() { $fields = array(); foreach ($this->getHeaders() as $header => $value) { $fields[] = sprintf('%s: %s', $header, $value); } return $fields; } /** * @return string */ public function getHeadersAsString() { $headers = $this->getHeaders(); $return = ''; foreach ($headers as $h => $v) { $return .= sprintf("%s: %s\r\n", $h, $v); } return $return . "\r\n"; } /** * Set a http header for the request. * * @param string $header * @param string $value * @throws \Exception */ public function setHeader($header, $value) { if (is_array($value)) { throw new \Exception('Could not set the header: ' . $header); } $this->headers[$header] = $value; } /** * @inheritdoc */ public function getBody() { return $this->body; } /** * Sets the body of the request. * * @param string $body * @return Request */ public function setBody($body) { $this->body = $body; $this->setHeader('Content-Length', strlen($body)); return $this; } /** * @inheritdoc */ public function getPath() { return $this->path; } /** * @param string $host * @return Request */ public function setPath($path) { $this->path = $path; return $this; } } php-client/src/Bitpay/Client/Client.php000075500000056564152503640360014022 0ustar00network = $network; } /** * Set the Public Key to use to help identify who you are to BitPay. Please * note that you must first pair your keys and get a token in return to use. * * @param PublicKey $key */ public function setPublicKey(PublicKey $key) { $this->publicKey = $key; } /** * Set the Private Key to use, this is used when signing request strings * * @param PrivateKey $key */ public function setPrivateKey(PrivateKey $key) { $this->privateKey = $key; } /** * Set the network adapter object to use. * * @param AdapterInterface $adapter */ public function setAdapter(AdapterInterface $adapter) { $this->adapter = $adapter; } /** * Assigns the token to use for a request. * * @param TokenInterface $token * @return ClientInterface */ public function setToken(TokenInterface $token) { $this->token = $token; return $this; } /** * @inheritdoc */ public function createInvoice(InvoiceInterface $invoice) { $request = $this->createNewRequest(); $request->setMethod(Request::METHOD_POST); $request->setPath('invoices'); $currency = $invoice->getCurrency(); $item = $invoice->getItem(); $buyer = $invoice->getBuyer(); $buyerAddress = $buyer->getAddress(); $this->checkPriceAndCurrency($item->getPrice(), $currency->getCode()); $body = array( 'price' => $item->getPrice(), 'currency' => $currency->getCode(), 'posData' => $invoice->getPosData(), 'notificationURL' => $invoice->getNotificationUrl(), 'transactionSpeed' => $invoice->getTransactionSpeed(), 'fullNotifications' => $invoice->isFullNotifications(), 'notificationEmail' => $invoice->getNotificationEmail(), 'redirectURL' => $invoice->getRedirectUrl(), 'orderID' => $invoice->getOrderId(), 'itemDesc' => $item->getDescription(), 'itemCode' => $item->getCode(), 'physical' => $item->isPhysical(), 'buyerName' => trim(sprintf('%s %s', $buyer->getFirstName(), $buyer->getLastName())), 'buyerAddress1' => isset($buyerAddress[0]) ? $buyerAddress[0] : '', 'buyerAddress2' => isset($buyerAddress[1]) ? $buyerAddress[1] : '', 'buyerCity' => $buyer->getCity(), 'buyerState' => $buyer->getState(), 'buyerZip' => $buyer->getZip(), 'buyerCountry' => $buyer->getCountry(), 'buyerEmail' => $buyer->getEmail(), 'buyerPhone' => $buyer->getPhone(), 'guid' => Util::guid(), 'token' => $this->token->getToken(), ); $request->setBody(json_encode($body)); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($request); $body = json_decode($this->response->getBody(), true); $error_message = false; $error_message = (!empty($body['error'])) ? $body['error'] : $error_message; $error_message = (!empty($body['errors'])) ? $body['errors'] : $error_message; $error_message = (is_array($error_message)) ? implode("\n", $error_message) : $error_message; if (false !== $error_message) { throw new \Exception($error_message); } $data = $body['data']; $invoiceToken = new \Bitpay\Token(); $paymentUrls = new \Bitpay\PaymentUrlSet(); $invoice ->setToken($invoiceToken->setToken($data['token'])) ->setId($data['id']) ->setUrl($data['url']) ->setStatus($data['status']) ->setBtcPrice($data['btcPrice']) ->setPrice($data['price']) ->setInvoiceTime($data['invoiceTime'] / 1000) ->setExpirationTime($data['expirationTime'] / 1000) ->setCurrentTime($data['currentTime'] / 1000) ->setBtcPaid($data['btcPaid']) ->setRate($data['rate']) ->setExceptionStatus($data['exceptionStatus']) ->setPaymentUrls($paymentUrls->setUrls($data['paymentUrls'])); return $invoice; } /** * @inheritdoc */ public function getCurrencies() { $this->request = $this->createNewRequest(); $this->request->setMethod(Request::METHOD_GET); $this->request->setPath('currencies'); $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (empty($body['data'])) { throw new \Exception('Error with request: no data returned'); } $currencies = $body['data']; array_walk($currencies, function (&$value, $key) { $currency = new \Bitpay\Currency(); $currency ->setCode($value['code']) ->setSymbol($value['symbol']) ->setPrecision($value['precision']) ->setExchangePctFee($value['exchangePctFee']) ->setPayoutEnabled($value['payoutEnabled']) ->setName($value['name']) ->setPluralName($value['plural']) ->setAlts($value['alts']) ->setPayoutFields($value['payoutFields']); $value = $currency; }); return $currencies; } /** * @inheritdoc */ public function createPayout(PayoutInterface $payout) { $request = $this->createNewRequest(); $request->setMethod($request::METHOD_POST); $request->setPath('payouts'); $amount = $payout->getAmount(); $currency = $payout->getCurrency(); $effectiveDate = $payout->getEffectiveDate(); $token = $payout->getToken(); $body = array( 'token' => $token->getToken(), 'amount' => $amount, 'currency' => $currency->getCode(), 'instructions' => array(), 'effectiveDate' => $effectiveDate, 'pricingMethod' => $payout->getPricingMethod(), 'guid' => Util::guid(), ); // Optional foreach (array('reference','notificationURL','notificationEmail') as $value) { $function = 'get' . ucfirst($value); if ($payout->$function() != null) { $body[$value] = $payout->$function(); } } // Add instructions foreach ($payout->getInstructions() as $instruction) { $body['instructions'][] = array( 'label' => $instruction->getLabel(), 'address' => $instruction->getAddress(), 'amount' => $instruction->getAmount() ); } $request->setBody(json_encode($body)); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($request); $body = json_decode($this->response->getBody(), true); $error_message = false; $error_message = (!empty($body['error'])) ? $body['error'] : $error_message; $error_message = (!empty($body['errors'])) ? $body['errors'] : $error_message; $error_message = (is_array($error_message)) ? implode("\n", $error_message) : $error_message; if (false !== $error_message) { throw new \Exception($error_message); } $data = $body['data']; $payout ->setId($data['id']) ->setAccountId($data['account']) ->setResponseToken($data['token']) ->setStatus($data['status']); foreach ($data['instructions'] as $c => $instruction) { $payout->updateInstruction($c, 'setId', $instruction['id']); } return $payout; } /** * @inheritdoc */ public function getPayouts($status = null) { $request = $this->createNewRequest(); $request->setMethod(Request::METHOD_GET); $path = 'payouts?token=' . $this->token->getToken() . (($status == null) ? '' : '&status=' . $status); $request->setPath($path); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); $error_message = false; $error_message = (!empty($body['error'])) ? $body['error'] : $error_message; $error_message = (!empty($body['errors'])) ? $body['errors'] : $error_message; $error_message = (is_array($error_message)) ? implode("\n", $error_message) : $error_message; if (false !== $error_message) { throw new \Exception($error_message); } $payouts = array(); array_walk($body['data'], function ($value, $key) use (&$payouts) { $payout = new \Bitpay\Payout(); $payout ->setId($value['id']) ->setAccountId($value['account']) ->setCurrency(new \Bitpay\Currency($value['currency'])) ->setEffectiveDate($value['effectiveDate']) ->setRequestdate($value['requestDate']) ->setPricingMethod($value['pricingMethod']) ->setStatus($value['status']) ->setAmount($value['amount']) ->setResponseToken($value['token']) ->setRate(@$value['rate']) ->setBtcAmount(@$value['btc']) ->setReference(@$value['reference']) ->setNotificationURL(@$value['notificationURL']) ->setNotificationEmail(@$value['notificationEmail']); array_walk($value['instructions'], function ($value, $key) use (&$payout) { $instruction = new \Bitpay\PayoutInstruction(); $instruction ->setId($value['id']) ->setLabel($value['label']) ->setAddress($value['address']) ->setAmount($value['amount']) ->setStatus($value['status']); array_walk($value['transactions'], function ($value, $key) use (&$instruction) { $transaction = new \Bitpay\PayoutTransaction(); $transaction ->setTransactionId($value['txid']) ->setAmount($value['amount']) ->setDate($value['date']); $instruction->addTransaction($transaction); }); $payout->addInstruction($instruction); }); $payouts[] = $payout; }); return $payouts; } /** * @inheritdoc */ public function deletePayout(PayoutInterface $payout) { $request = $this->createNewRequest(); $request->setMethod(Request::METHOD_DELETE); $request->setPath(sprintf('payouts/%s?token=%s', $payout->getId(), $payout->getResponseToken())); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (empty($body['data'])) { throw new \Exception('Error with request: no data returned'); } $data = $body['data']; $payout->setStatus($data['status']); return $payout; } /** * @inheritdoc */ public function getPayout($payoutId) { $request = $this->createNewRequest(); $request->setMethod(Request::METHOD_GET); $request->setPath(sprintf('payouts/%s?token=%s', $payoutId, $this->token->getToken())); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (empty($body['data'])) { throw new \Exception('Error with request: no data returned'); } $data = $body['data']; $payout = new \Bitpay\Payout(); $payout ->setId($data['id']) ->setAccountId($data['account']) ->setStatus($data['status']) ->setCurrency(new \Bitpay\Currency($data['currency'])) ->setRate(@$data['rate']) ->setAmount($data['amount']) ->setBtcAmount(@$data['btc']) ->setPricingMethod(@$data['pricingMethod']) ->setReference(@$data['reference']) ->setNotificationEmail(@$data['notificationEmail']) ->setNotificationUrl(@$data['notificationURL']) ->setRequestDate($data['requestDate']) ->setEffectiveDate($data['effectiveDate']) ->setResponseToken($data['token']); array_walk($data['instructions'], function ($value, $key) use (&$payout) { $instruction = new \Bitpay\PayoutInstruction(); $instruction ->setId($value['id']) ->setLabel($value['label']) ->setAddress($value['address']) ->setStatus($value['status']) ->setAmount($value['amount']) ->setBtc($value['btc']); array_walk($value['transactions'], function ($value, $key) use (&$instruction) { $transaction = new \Bitpay\PayoutTransaction(); $transaction ->setTransactionId($value['txid']) ->setAmount($value['amount']) ->setDate($value['date']); $instruction->addTransaction($transaction); }); $payout->addInstruction($instruction); }); return $payout; } /** * @inheritdoc */ public function getTokens() { $request = $this->createNewRequest(); $request->setMethod(Request::METHOD_GET); $request->setPath('tokens'); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (empty($body['data'])) { throw new \Exception('Error with request: no data returned'); } $tokens = array(); array_walk($body['data'], function ($value, $key) use (&$tokens) { $key = current(array_keys($value)); $value = current(array_values($value)); $token = new \Bitpay\Token(); $token ->setFacade($key) ->setToken($value); $tokens[$token->getFacade()] = $token; }); return $tokens; } /** * @inheritdoc */ public function createToken(array $payload = array()) { if (isset($payload['pairingCode']) && 1 !== preg_match('/^[a-zA-Z0-9]{7}$/', $payload['pairingCode'])) { throw new \Exception('[ERROR] In Client::createToken(): The pairing code provided is not legal.'); } $this->request = $this->createNewRequest(); $this->request->setMethod(Request::METHOD_POST); $this->request->setPath('tokens'); $payload['guid'] = Util::guid(); $this->request->setBody(json_encode($payload)); $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (isset($body['error'])) { throw new \Bitpay\Client\BitpayException($this->response->getStatusCode() . ': ' . $body['error']); } $tkn = $body['data'][0]; $createdAt = new \DateTime(); $pairingExpiration = new \DateTime(); $token = new \Bitpay\Token(); $token ->setPolicies($tkn['policies']) ->setToken($tkn['token']) ->setFacade($tkn['facade']) ->setCreatedAt($createdAt->setTimestamp(floor($tkn['dateCreated'] / 1000))); if (isset($tkn['resource'])) { $token->setResource($tkn['resource']); } if (isset($tkn['pairingCode'])) { $token->setPairingCode($tkn['pairingCode']); $token->setPairingExpiration($pairingExpiration->setTimestamp(floor($tkn['pairingExpiration'] / 1000))); } return $token; } /** * Returns the Response object that BitPay returned from * the request that was sent. * * @return ResponseInterface */ public function getResponse() { return $this->response; } /** * Returns the request object that was sent to BitPay. * * @return RequestInterface */ public function getRequest() { return $this->request; } /** * @inheritdoc */ public function getInvoice($invoiceId) { $this->request = $this->createNewRequest(); $this->request->setMethod(Request::METHOD_GET); if ($this->token->getFacade() === 'merchant') { $this->request->setPath(sprintf('invoices/%s?token=%s', $invoiceId, $this->token->getToken())); $this->addIdentityHeader($this->request); $this->addSignatureHeader($this->request); } else { $this->request->setPath(sprintf('invoices/%s', $invoiceId)); } $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (isset($body['error'])) { throw new \Exception($body['error']); } $data = $body['data']; $invoice = new \Bitpay\Invoice(); $invoiceToken = new \Bitpay\Token(); $paymentUrls = new \Bitpay\PaymentUrlSet(); $invoice ->setToken($invoiceToken->setToken($data['token'])) ->setUrl($data['url']) ->setPosData($data['posData']) ->setStatus($data['status']) ->setBtcPrice($data['btcPrice']) ->setPrice($data['price']) ->setCurrency(new \Bitpay\Currency($data['currency'])) ->setOrderId($data['orderId']) ->setInvoiceTime($data['invoiceTime'] / 1000) ->setExpirationTime($data['expirationTime'] / 1000) ->setCurrentTime($data['currentTime'] / 1000) ->setId($data['id']) ->setBtcPaid($data['btcPaid']) ->setRate($data['rate']) ->setExceptionStatus($data['exceptionStatus']); if (isset($data['paymentUrls'])) { $invoice ->setPaymentUrls($paymentUrls->setUrls($data['paymentUrls'])); } return $invoice; } /** * @param RequestInterface $request * @return ResponseInterface */ public function sendRequest(RequestInterface $request) { if (null === $this->adapter) { // Uses the default adapter $this->adapter = new \Bitpay\Client\Adapter\CurlAdapter(); } return $this->adapter->sendRequest($request); } /** * @param RequestInterface $request * @throws \Exception */ protected function addIdentityHeader(RequestInterface $request) { if (null === $this->publicKey) { throw new \Exception('[ERROR] In Client::addIdentityHeader(): No public key value found. Please set your kublic key first before you can add the x-identity header.'); } $request->setHeader('x-identity', (string) $this->publicKey); } /** * @param RequestInterface $request * @throws \Exception */ protected function addSignatureHeader(RequestInterface $request) { if (null === $this->privateKey) { throw new \Exception('Please set your Private Key'); } if (true == property_exists($this->network, 'isPortRequiredInUrl')) { if ($this->network->isPortRequiredInUrl === true) { $url = $request->getUriWithPort(); } else { $url = $request->getUri(); } } else { $url = $request->getUri(); } $message = sprintf( '%s%s', $url, $request->getBody() ); $signature = $this->privateKey->sign($message); $request->setHeader('x-signature', $signature); } /** * @return RequestInterface */ protected function createNewRequest() { $request = new Request(); $request->setHost($this->network->getApiHost()); $request->setPort($this->network->getApiPort()); $this->prepareRequestHeaders($request); return $request; } /** * Prepares the request object by adding additional headers * * @see http://en.wikipedia.org/wiki/User_agent * @param RequestInterface $request */ protected function prepareRequestHeaders(RequestInterface $request) { $request->setHeader( 'User-Agent', sprintf('%s/%s (PHP %s)', self::NAME, self::VERSION, phpversion()) ); $request->setHeader('X-BitPay-Plugin-Info', sprintf('%s/%s', self::NAME, self::VERSION)); $request->setHeader('Content-Type', 'application/json'); $request->setHeader('X-Accept-Version', '2.0.0'); } /** * @param string $price * @param string $currency * @throws \Exception */ protected function checkPriceAndCurrency($price, $currency) { // Get the decimal precision of the price $decimalPosition = strpos($price, '.'); if ($decimalPosition == 0) { $decimalPrecision = 0; } else { $decimalPrecision = strlen(substr($price, $decimalPosition + 1)); } if (($decimalPrecision > 2 && $currency != 'BTC') || $decimalPrecision > 6) { throw new \Exception('Incorrect price format or currency type.'); } } } php-client/src/Bitpay/Client/Response.php000075500000005265152503640360014372 0ustar00headers = array(); $this->raw = $raw; } /** * Returns the raw http response * * @return string */ public function __toString() { return (string)$this->raw; } /** * @param Response */ public static function createFromRawResponse($rawResponse) { $response = new self($rawResponse); $lines = preg_split('/(\\r?\\n)/', $rawResponse); $linesLen = count($lines); for ($i = 0; $i < $linesLen; $i++) { if (0 == $i) { preg_match('/^HTTP\/(\d\.\d)\s(\d+)\s(.+)/', $lines[$i], $statusLine); $response->setStatusCode($statusCode = $statusLine[2]); continue; } if (empty($lines[$i])) { $body = array_slice($lines, $i + 1); $response->setBody(implode("\n", $body)); break; } if (strpos($lines[$i], ':')) { $headerParts = explode(':', $lines[$i]); $response->setHeader($headerParts[0], $headerParts[1]); } } return $response; } /** * @inheritdoc */ public function getStatusCode() { return $this->statusCode; } /** * @param integer * @return Response */ public function setStatusCode($statusCode) { $this->statusCode = (integer)$statusCode; return $this; } /** * @inheritdoc */ public function getBody() { return $this->body; } /** * Set the body of the response * * @param string $body * @return Response */ public function setBody($body) { $this->body = $body; return $this; } /** * @inheritdoc */ public function getHeaders() { return $this->headers; } /** * @param string $header * @param string $value * @return Response */ public function setHeader($header, $value) { $this->headers[$header] = $value; return $this; } } php-client/src/Bitpay/Client/ClientInterface.php000075500000003513152503640360015625 0ustar00curlOptions = $curlOptions; } /** * Returns an array of cURL settings to use * * @return array */ public function getCurlOptions() { return $this->curlOptions; } /** * @inheritdoc */ public function sendRequest(\Bitpay\Client\Request $request) { $curl = curl_init(); if ($curl === false) { throw new \Exception('[ERROR] In CurlAdapter::sendRequest(): Could not initialize cURL.'); } $default_curl_options = $this->getCurlDefaultOptions($request); foreach ($this->getCurlOptions() as $curl_option_key => $curl_option_value) { if (is_null($curl_option_value) === false) { $default_curl_options[$curl_option_key] = $curl_option_value; } } curl_setopt_array($curl, $default_curl_options); if (RequestInterface::METHOD_POST == $request->getMethod()) { curl_setopt_array( $curl, array( CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $request->getBody(), ) ); } $raw = curl_exec($curl); if ($raw === false) { $errorMessage = curl_error($curl); curl_close($curl); throw new \Exception('[ERROR] In CurlAdapter::sendRequest(): curl_exec failed with the error "' . $errorMessage . '".'); } /** @var Response */ $response = Response::createFromRawResponse($raw); curl_close($curl); return $response; } /** * Returns an array of default cURL settings to use. * * @param \Bitpay\Client\Request $request * @return array */ private function getCurlDefaultOptions(\Bitpay\Client\Request $request) { return array( CURLOPT_URL => $request->getUri(), CURLOPT_PORT => $request->getPort(), CURLOPT_CUSTOMREQUEST => $request->getMethod(), CURLOPT_HTTPHEADER => $request->getHeaderFields(), CURLOPT_TIMEOUT => 10, CURLOPT_SSL_VERIFYPEER => 1, CURLOPT_SSL_VERIFYHOST => 2, CURLOPT_CAINFO => __DIR__ . '/ca-bundle.crt', CURLOPT_RETURNTRANSFER => true, CURLOPT_FORBID_REUSE => 1, CURLOPT_FRESH_CONNECT => 1, CURLOPT_HEADER => true, ); } } php-client/src/Bitpay/Client/ResponseInterface.php000075500000001061152503640360016201 0ustar00 $value array of http headers * * @return array */ public function getHeaders(); } php-client/src/Bitpay/Client/BitpayException.php000075500000000364152503640360015676 0ustar00 Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal > in the Software without restriction, including without limitation the rights > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > copies of the Software, and to permit persons to whom the Software is > furnished to do so, subject to the following conditions: > > The above copyright notice and this permission notice shall be included in > all copies or substantial portions of the Software. > > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > THE SOFTWARE.