有没有更好的方法来获取 PHP 中的货币汇率?

Is there any better way to get Currency Exchange Rate in PHP?

以下代码的货币汇率有时有效,有时无效,而且一点也不可靠。在PHP中有没有更好的方法来获取货币汇率?

public function getJPYtoUSDExchangeRate(){
    $from    = 'JPY';
    $to    = 'USD';
    $amount  = 1;
    $data = file_get_contents("https://finance.google.com/finance/converter?a=$amount&from=$from&to=$to");
    preg_match("/<span class=bld>(.*)<\/span>/",$data, $converted);
    $converted = preg_replace("/[^0-9.]/", "", $converted[1][0]);
    return number_format(round($converted, 3),2);
}

您有几个问题:

  • 您不是在调用实际的 API,您是在抓取网页,这意味着:
    • 您很可能违反了 Google 的服务条款
    • 如果您过于频繁地获取此页面,您更有可能在某个时候受到速率限制(或被检测为滥用和列入黑名单)
    • 您依赖于对网页HTML结构所做的任何更改
  • 每次需要将金额转换为另一种货币时,您都在抓取页面,这意味着任何失败都会导致您的货币转换失败。

你应该做什么:

  • 从合法的 Feed 或 API
  • 加载汇率
  • 定期加载它们(例如通过 cron 作业)并将它们保存到本地数据库,这将是用于执行货币转换

这样,即使 API 调用失败,您仍然可以获得稍微过时的汇率,这在大多数情况下比失败要好。


您在哪里找到 trustable 汇率源?

有很多 API 提供此服务,无论是否免费。

我知道的一个很好的来源是欧洲中央银行,它提供了一个已经存在多年的 XML feed 并提供了 32 种货币相对于 EUR.

的汇率

OpenExchangeRates 还提供每月 1,000 次请求限制的免费计划,这足以每小时刷新一次。它提供了 170 种货币的汇率,相对于 USD

如何将值存储在数据库中?

无论您选择哪个提要,您都需要解析它(如果 XML)或 json_decode() 它(如果 JSON)并将值存储在您的数据库中。理想情况下,每天甚至每小时为 运行 导入脚本设置一个 cron 作业。

实际的解析和导入步骤超出了这个问题的范围,但我们假设一个简单的 MySQL table 保存记录:

CREATE TABLE exchange_rate(
  target_currency CHAR(3) COLLATE ascii_bin NOT NULL PRIMARY KEY,
  exchange_rate DOUBLE NOT NULL
);

如何根据相对于单一货币的汇率正确处理货币换算?

这是我提出的问题 answered recently. The feeds above give you rates to convert the base currency (EUR or USD) to another currency, but do not give you a clue on how to convert between two arbitrary currencies. I would suggest you use a proper library that handles these conversions for you, such as brick/money - 免责声明:我是作者

以下是如何配置它以从上面的 table 加载汇率:

use Brick\Money\CurrencyConverter;
use Brick\Money\ExchangeRateProvider\PDOProvider;
use Brick\Money\ExchangeRateProvider\PDOProviderConfiguration;
use Brick\Money\ExchangeRateProvider\BaseCurrencyProvider;

// set to whatever your rates are relative to
$baseCurrency = 'USD';

// use your own credentials, or re-use your existing PDO connection
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');

$configuration = new PDOProviderConfiguration();

$configuration->tableName                = 'exchange_rate';
$configuration->exchangeRateColumnName   = 'exchange_rate';
$configuration->targetCurrencyColumnName = 'target_currency';
$configuration->sourceCurrencyCode       = $baseCurrency;

// this provider loads exchange rates from your database
$provider = new PDOProvider($pdo, $configuration);

// this provider calculates exchange rates relative to the base currency
$provider = new BaseCurrencyProvider($provider, $baseCurrency);

// this currency converter can now handle any currency pair
$converter = new CurrencyConverter($provider);

以及您将如何使用它:

use Brick\Math\RoundingMode;
use Brick\Money\Money;

$money = Money::of(10, 'EUR'); // EUR 10.00
$converter->convert($money, 'CAD', RoundingMode::DOWN); // CAD 15.27

CurrencyFreaks API 以与多种编程语言兼容的 JSON 和 XML 格式为全球 179 种货币提供可靠的汇率。通过使用 CurrencyFreaks API,您还可以更改 'base' 货币并可以获得特定货币的汇率。

这是一个简单的货币汇率端点,使用PHP:

setUrl('https://api.currencyfreaks.com/latest
    ?apikey=YOUR_APIKEY
    &base=GBP');
$request->setMethod(HTTP_Request2::METHOD_GET);
$request->setConfig(array(
  'follow_redirects' => TRUE
));
try {
  $response = $request->send();
  if ($response->getStatus() == 200) {
    echo $response->getBody();
  }
  else {
    echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
    $response->getReasonPhrase();
  }
}
catch(HTTP_Request2_Exception $e) {
  echo 'Error: ' . $e->getMessage();
}

JSON 响应将是:

{
    "date": "2020-10-06 11:22:00+00",
    "base": "GBP",
    "rates": {
        "FJD": "2.737385252915371",
        "MXN": "27.74546375788785",
        "STD": "27185.017172962733",
        "LVL": "0.8482572402792966",
        "SCR": "23.257414775003944",
        "CDF": "2535.4260357935937",
        "BBD": "2.585121591194042",
        "GTQ": "10.055244048403818",
        "CLP": "1031.8523300993463",
        "HNL": "31.82062875327341",
        "UGX": "4769.159332676713",
        "ZAR": "21.445845580346873",
        "TND": "3.542262860333636",
        "CUC": "1.2926654930214643",
        "BSD": "1.292560795597021",
        "SLL": "12676.789824444395",
        "SDG": "71.5109260164052",
        "IQD": "1542.8992384231794",
        "GMD": "66.89002117214584",
        "CUP": "34.25286108332106",
        "TWD": "37.17921872455271",
        "RSD": "128.99756740058268",
        "DOP": "75.46618143934401",
        "KMF": "540.1610026652604",
          .
          .
          .
        [179 Currencies]
    }
}

希望有用。

加拿大银行为以下货币提供 RSS 提要: AUD、BRL、CNY、EUR、HKD、INR、IDR、JPY、MXN、NZD、NOK、PEN、RUB、SAR、SGD、ZAR、KRW、SEK、CHF、TWD、TRY、GBP、USD

这是一种无需 API 或第 3 方服务即可获得货币换算的方法:

<?php

class EXCHANGE {

    public $Rates;
    public $Rate;

    public function __construct(){
        $this->Rates = $this->fetchAllRates();
        foreach($this->Rates as $currency => $rate){
            $this->Rate[$currency] = $rate['latest'];
        }
    }

    public function fetchAllRates(){
        $currencies = ["AUD","BRL","CNY","EUR","HKD","INR","IDR","JPY","MXN","NZD","NOK","PEN","RUB","SAR","SGD","ZAR","KRW","SEK","CHF","TWD","TRY","GBP","USD"];
        $cURL = curl_init();
        curl_setopt($cURL, CURLOPT_URL, "https://www.bankofcanada.ca/valet/observations/group/FX_RATES_DAILY/json?start_date=2010-01-01");
        curl_setopt($cURL, CURLOPT_RETURNTRANSFER, 1);
        $rates = curl_exec($cURL);
        curl_close($cURL);
        $rates = json_decode($rates,true)['observations'];
        foreach($currencies as $currency){
            foreach($rates as $rate){
                $AllRates[$currency][$rate['d']] = $rate['FX'.$currency.'CAD']['v'];
                $AllRates[$currency]['latest'] = $rate['FX'.$currency.'CAD']['v'];
            }
        }
        return $AllRates;
    }

    public function convert($value,$from,$to){
        if($to == "CAD"){ return $value*$this->Rate[$from]; }
        else { return ($value*$this->Rate[$from])/$this->Rate[$to]; }
    }

}

$Exchange = new EXCHANGE();

foreach($Exchange->Rate as $currency => $rate){
    echo $currency.': '.$rate."<br>\n"; // Listing all the exchange rates
}

echo "Converting 2.00 USD to CAD : ".$Exchange->convert(2,"USD","CAD")."\n"; //2022-02-23 = 2.5486

echo "Converting 2.00 USD to AUD : ".$Exchange->convert(2,"USD","AUD")."\n"; //2022-02-23 =  2.7708197434225

更新: 我最初忘记了转换方法。

信息: class 使用的是加拿大银行的 RSS 提要。它不是最准确的数据,因为它每个工作日只更新一次。 $Rate 属性 包含 CAD 货币的汇率。因此要转换其他货币,它首先将初始货币转换为 CAD,然后再转换为新货币。因此,在上面提供的示例中,2.00 美元被转换为 2.5486 加元。然后除以澳元汇率得到2.7708197434225澳元。