使用PHP的API请求缓慢加载时间

时间:2015-10-15 15:05:54

标签: php api bitcoin

我正在使用PHP从多个比特币交易所获取价格数据和交易量数据,但是当你加载页面时,它需要接近20秒。如何让加载时间更好?我认为它与卷曲有关。

 <?php
    function getData($url) {
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    $rawData = curl_exec($curl);
    curl_close($curl);
    return json_decode($rawData, true);
    }
    //BTC Volume LocalBitcoins
    $BTCVolumeLocal = getData('https://localbitcoins.com/bitcoinaverage/ticker-all-currencies/');
    $LocalVolume = $BTCVolumeLocal["USD"]["volume_btc"];

    //BTC Volume BTCE
    $BTCVolumeBTCE = getData('https://btc-e.com/api/3/ticker/btc_usd');
    $BTCEVolume = $BTCVolumeBTCE["btc_usd"]["vol_cur"];

    //BTC Volume Bitstamp
    $BTCVolumeStamp = getData('https://www.bitstamp.net/api/ticker/');
    $StampVolume = $BTCVolumeStamp["volume"];

    //BTC Volume Bitfinex
    $BTCVolumeFinex = getData('https://api.bitfinex.com/v1/pubticker/btcusd');
    $FinexVolume = $BTCVolumeFinex["volume"];

    //BTC Volume OKCoin
    $BTCVolumeOK = getData('https://www.okcoin.com/api/ticker.do?ok=1');
    $OKCoinVolume = $BTCVolumeOK["ticker"]["vol"];

    //BTC Volume LakeBTC
    $BTCVolumeLake = getData('https://www.lakebtc.com/api_v1/ticker');
    $LakeVolume = $BTCVolumeLake["USD"]["volume"];

    //Totals the Volumes
    $TotalVolume = $LakeVolume + $FinexVolume + $OKCoinVolume + $StampVolume + $BTCEVolume + $LocalVolume;
    //Percents of Total Volume
    $BTCEPercent = $BTCEVolume / $TotalVolume;
    $StampPercent = $StampVolume / $TotalVolume;
    $FinexPercent = $FinexVolume / $TotalVolume;
    $OKPercent = $OKCoinVolume / $TotalVolume;
    $LakePercent = $LakeVolume / $TotalVolume;
    $LocalPercent = $LocalVolume / $TotalVolume;

    //BTC Price BTCE
    $BTCPriceBTCE = getData('https://btc-e.com/api/3/ticker/btc_usd');
    $BTCEPrice = $BTCPriceBTCE["btc_usd"]["last"];

    //BTC Price Bitstamp
    $BTCPriceStamp = getData('https://www.bitstamp.net/api/ticker/');
    $StampPrice = $BTCPriceStamp["last"];

    //BTC Price Bitfinex
    $BTCPriceFinex = getData('https://api.bitfinex.com/v1/pubticker/btcusd');
    $FinexPrice = $BTCPriceFinex["last_price"];

    //BTC Price OKCoin
    $BTCPriceOK = getData('https://www.okcoin.com/api/ticker.do?ok=1');
    $OKPrice = $BTCPriceOK["ticker"]["last"];

    //BTC Price LakeBTC
    $BTCPriceLake = getData('https://www.lakebtc.com/api_v1/ticker');
    $LakePrice = $BTCPriceLake["USD"]["last"];

    //BTC Price LocalBitcoins
    $BTCPriceLocal = getData('https://localbitcoins.com/bitcoinaverage/ticker-all-currencies/');
    $LocalPrice = $BTCPriceLocal["USD"]["avg_1h"];

    //BTC Price * Percent
    $BTCEPricePercent = $BTCEPrice * $BTCEPercent;
    $StampPricePercent = $StampPrice * $StampPercent;
    $FinexPricePercent = $FinexPrice * $FinexPercent;
    $OKPricePercent = $OKPrice * $OKPercent;
    $LakePricePercent = $LakePrice * $LakePercent;
    $LocalPricePercent = $LocalPrice * $LocalPercent;

    //Bitcoin Price
    $bitcoinPrice = round($LakePricePercent + $OKPricePercent + $FinexPricePercent + $StampPricePercent + $BTCEPricePercent + $LocalPricePercent, 2);

    ?>

4 个答案:

答案 0 :(得分:4)

如果API响应速度不够快且不受您的控制,您可能无法更改此内容。

并行查询它们可能会加快速度,但正如评论中所提到的,使用PHP通常并不容易。

如果只是页面的加载时间,您可以缓存API查询的结果:

  • 将API请求放在cronjob中,每隔x分钟自动调用一次。根据输入数据的变化速度,这可能低至1分钟(遗憾的是,这意味着您将创建大量流量),或者您可以每小时查询一次,如果可以计算的话。
  • 将结果保存到本地数据库或缓存(MySQL,Redis,Memcache,...)
  • 对于您的计算,只读取您的本地值副本,这比每次查询服务要快得多

答案 1 :(得分:2)

您有12个服务电话,20秒是真实的。我不熟悉您的应用,但您可以考虑实施一些缓存(将下载的数据保存到文件中,然后从下载的文件中加载)。

$url = 'http://www.example.com';
$content = '';
$file_name = 'tmp/cache.txt';

if(file_exists($file_name))){
    $content = file_get_contents($file_name);
}else{
    $content = file_get_contents($url);
    //or $content = getData($url);
    file_put_contents($file_name, $content);
}


function getData($url) {
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    $rawData = curl_exec($curl);
    curl_close($curl);
    return json_decode($rawData, true);
}

答案 2 :(得分:1)

多线程和/或缓存,朋友。

PHP中的多线程并不比任何其他语言更难。您可以在此处找到相关说明:How can one use multi threading in PHP applications

你可以使用Memcache或Redis进行简单的缓存,并且有各种各样的教程和帮助在Web上使用它们来缓存PHP中的内容。

答案 3 :(得分:1)

我发现使用ajax结果都很快回来了,因为请求是异步运行的,到目前为止,这是在进行中......如果其他人可以看到我认为从这种方法中看到的好处毫无疑问,他们会指出它。

这个想法是一个js函数向php脚本发送一系列ajax请求,然后将curl请求发送给给定的各种比特币url。每个请求都设置为携带从请求返回的字段 - 然后php脚本向下钻取数据并找到该信息并返回到js。

计算各种百分比仍然是一个问题,因为您不必知道所有请求何时完成。我猜promises可能有用吗?

当然使用ajax可以让页面快速加载 - 然后结果会随着&#39;直到完成.....

bitcoin.php
-----------
<?php
    if( $_SERVER['REQUEST_METHOD']=='POST' ){

        $cacert='c:\wwwroot\cacert.pem';


        /* Two of the three params sent via ajax */
        $url=$_POST['url'];
        $fields=$_POST['fields'];

        /* $fields might be a comma separated list of fields, or simply one - we want an array */
        $params=( !empty( $fields ) && strstr( $fields, ',' ) ) ? explode( ',', $fields ) : (array)$fields;


        $curl=curl_init( $url );

        if( parse_url( $url, PHP_URL_SCHEME )=='https' ){
            curl_setopt( $curl, CURLOPT_SSL_VERIFYPEER, FALSE );
            curl_setopt( $curl, CURLOPT_SSL_VERIFYHOST, 2 );
            curl_setopt( $curl, CURLOPT_CAINFO, realpath( $cacert ) );
        }

        curl_setopt( $curl, CURLOPT_URL, $url );
        curl_setopt( $curl, CURLOPT_HEADER, false );
        curl_setopt( $curl, CURLOPT_FRESH_CONNECT, true );
        curl_setopt( $curl, CURLOPT_FORBID_REUSE, true );
        curl_setopt( $curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1 );
        curl_setopt( $curl, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_OLDEST );
        curl_setopt( $curl, CURLOPT_BINARYTRANSFER, true );
        curl_setopt( $curl, CURLOPT_AUTOREFERER, true );
        curl_setopt( $curl, CURLOPT_CONNECTTIMEOUT, 10 );
        curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
        curl_setopt( $curl, CURLOPT_USERAGENT, 'Bitcoin Fuzzer' );


        $data=trim( curl_exec( $curl ) );
        $status=curl_getinfo( $curl,CURLINFO_HTTP_CODE );
        curl_close( $curl );



        /* Deal with the response data */
        if( $status==200 ){

            $json=json_decode( $data );
            /* 
                Hack: 
                there must be a better way to drill down dynamically through
                an object structure but I was too tired to think straight

                This simply echos back the response for javascript to deal with
                but I guess one could make use of sessions to do the calculations
                in php rather than js
            */
            switch( count( $params ) ){
                case 1:
                    $p1=$params[0];
                    print_r( $json->$p1 );
                break;
                case 2:
                    $p1=$params[0];
                    $p2=$params[1];
                    print_r( $json->$p1->$p2 );
                break;
                case 3:
                    $p1=$params[0];
                    $p2=$params[1];
                    $p3=$params[2];
                    print_r( $json->$p1->$p2->$p3 );
                break;
            }
        }
    }
?>

html页面 - 头:

<script type='text/javascript' charset='utf-8'>
    /* simple ajax function */
    function _ajax( url, options ){
        var req=new XMLHttpRequest();
        var callback=options.hasOwnProperty('callback') ? options.callback : false;
        if( !callback ) return false;


        var headers={
            'Accept': "text/html, application/xml, application/json, text/javascript, "+"*"+"/"+"*"+"; charset=utf-8",
            'Content-type': 'application/x-www-form-urlencoded',
            'X-Requested-With': 'XMLHttpRequest'
        };

        var params=[];
        if( options.hasOwnProperty('params') && typeof( options.params )=='object' ){
            for( var n in options.params ) params.push( n + '=' + options.params[n] );
        }
        var args=options.hasOwnProperty('args') ? options.args : options;

        req.onreadystatechange=function(){
            if( req.readyState==4 ) {
               if( req.status==200 ) options.callback.call( this, req.response, args );
               else console.warn( 'Error: '+req.status+' status code returned' );
            }
        }

        req.open( 'POST', url, true );
        for( header in headers ) req.setRequestHeader( header, headers[ header ] );
        req.send( params.join('&') );
    }

    var volumes=[];
    var prices=[];
    var tot_vols=0;
    var tot_prices=0;

    function bitcoin(){
        var btc={
            vols:{
                'https:\/\/localbitcoins.com\/bitcoinaverage\/ticker-all-currencies\/':['USD','volume_btc'],
                'https:\/\/btc-e.com\/api\/3\/ticker\/btc_usd':['btc_usd','vol_cur'],
                'https:\/\/www.bitstamp.net\/api\/ticker\/':['volume'],
                'https:\/\/api.bitfinex.com\/v1\/pubticker\/btcusd':['volume'],
                'https:\/\/www.okcoin.com\/api\/ticker.do?ok=1':['ticker','vol'],
                'https:\/\/www.lakebtc.com\/api_v1\/ticker':['USD','volume']
            },
            prices:{
                'https:\/\/btc-e.com\/api\/3\/ticker\/btc_usd':['btc_usd','last'],
                'https:\/\/www.bitstamp.net\/api\/ticker\/':['last'],
                'https:\/\/api.bitfinex.com\/v1\/pubticker\/btcusd':['last_price'],
                'https:\/\/www.okcoin.com\/api\/ticker.do?ok=1':['ticker','last'],
                'https:\/\/www.lakebtc.com\/api_v1\/ticker':['USD','last'],
                'https:\/\/localbitcoins.com\/bitcoinaverage\/ticker-all-currencies\/':['USD','avg_1h']
            }
        };
        var url;
        var vols=btc.vols;
        var prices=btc.prices;

        for( url in vols ){
            getbitcoin.call( this, url, vols[url], 'volumes' );
        }

        for( url in prices ){
            getbitcoin.call( this, url, vols[url], 'prices' );  
        }
    }


    function getbitcoin( url, fields, type ){
        var options={
            callback:cbbtc,
            method:'POST',
            params:{
                'fields':fields,
                'type':type,
                'url':url
            }
        };
        _ajax.call( this, '/test/bitcoin.php', options );
    }

    function cbbtc(r,o){
        switch( o.params.type ){
            case 'volumes':
                tot_vols += parseFloat( r );
                volumes.push( parseFloat( r ) );
                document.getElementById('btc_vols').value=tot_vols;
            break;
            case 'prices':
                tot_prices += parseFloat( r );
                prices.push( parseFloat( r ) );
                document.getElementById('btc_prices').value=tot_prices;
            break;  
        }
    }           

    /* launch the function when the page is ready */
    document.addEventListener( 'DOMContentLoaded', bitcoin, false );
</script>

html page - body:

/* These simply receive values for testing */
<input type='text' id='btc_vols' />
<input type='text' id='btc_prices' />