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

5

以下代码的货币汇率有时有效,有时无效,不太可靠。有没有更好的方法在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);
}

3个回答

11

你有几个问题:

  • 你没有调用实际的API,而是在爬取网页,这意味着:
    • 你很可能违反了Google的服务条款
    • 如果你经常获取此页面,你更容易被限制速率(或被检测为滥用并列入黑名单)
    • 你依赖于网页HTML结构的任何更改
  • 每次需要将金额转换为另一种货币时,你都会从网页中提取数据,这意味着任何失败都会导致货币转换失败。

你应该做什么:

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

这样,即使API调用失败,你仍然可以访问略旧的汇率,这在大多数情况下比失败要好。


你在哪里可以找到可信赖的汇率数据源?

有很多API(免费或收费)提供此服务。

我知道一个好的数据源是欧洲央行,他们提供了一个XML数据源,已经存在多年,并提供32种货币相对于EUR的汇率。

OpenExchangeRates也提供了一个免费计划,每月限制1000个请求,足以每小时更新汇率。它提供了170种货币相对于USD的汇率。

如何在数据库中存储这些值?

无论你选择哪个数据源,你都需要解析它(如果是XML)或者使用json_decode()(如果是JSON),并将值存储在你的数据库中。最好设置一个cron job来每天甚至每小时运行你的导入脚本。

实际的解析和导入步骤超出了本问题的范围,但假设有一个简单的MySQL表来保存记录:

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

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

这是我最近回答过的问题。上面的信息提供了将基础货币(EURUSD)转换为另一种货币的汇率,但没有给出如何在两种任意货币之间进行转换的线索。我建议您使用一个能够为您处理这些转换的适当库,例如brick/money - 免责声明:我是作者

以下是如何配置它以从上述表格中加载您的汇率:

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

感谢Benjamin提供详细的解释。你的方法非常好。 - Pooja
2020年仍然没有可靠的免费货币中间市场汇率API吗? - Drunken M
欧洲央行的XML源码找到了!正在寻找美元类似的XML源码! - loretoparisi

5

CurrencyFreaks API提供179种货币的可靠汇率,支持多种编程语言的JSON和XML格式。使用CurrencyFreaks API,您还可以更改“基准”货币,并获取特定货币的汇率。

以下是使用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]
    }
}

我希望它能够工作。


1
加拿大银行为以下货币提供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或第三方服务进行货币转换的方法:
<?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

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

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


这是一个好的解决方案!顺便提一下,您在上面的代码片段中缺少类中的convert函数。 - loretoparisi
1
抱歉,刚刚更新了这个类。 - L. Ouellet
谢谢!现在它可以工作了,但我不确定这个API是如何工作的,因为它返回的值似乎与美元实时汇率https://www.exchangerates.org.uk/US-Dollar-USD-currency-table.html不同,你有什么想法吗? - loretoparisi
1
这个类基于加拿大银行的RSS订阅源。不幸的是,与上述付费服务相比,它的准确性较低。我的意思是它没有经常更新。(每天一次)您可以尝试从https://www.exchangerates.org.uk/data/currencies获取实时数据的信息。 - L. Ouellet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接