PHP WebShell
Текущая директория: /var/www/bitcardoApp/cron
Просмотр файла: update_coin_rates.php
<?php
/**
* update_coin_rates.php
* - Fetches live USD prices from CoinGecko for rows where auto_update=1
* - Applies percentage margin:
* sell_rate = live * (1 + margin_percent/100)
* buy_rate = live * (1 - margin_percent/100)
* - Writes sell_rate, buy_rate, updated_at into coin_rates
*
*/
@ini_set('display_errors', '0');
require_once __DIR__ . '/../config/db_config.php'; // must define $conn (mysqli)
// ---------- Config ----------
$LOG = '/var/log/coin_rates_updater.log'; // ensure cron user can write this
// Map your DB coin symbols -> CoinGecko IDs
$COINGECKO_MAP = [
'BTC' => 'bitcoin',
'ETH' => 'ethereum',
'SOL' => 'solana',
'USDT' => 'tether',
'USDC' => 'usd-coin',
// 'TRX' => 'tron',
// add more as needed
];
// ---------- Helpers ----------
function log_msg(string $lvl, string $msg, array $ctx = []): void {
global $LOG;
$line = ['ts'=>gmdate('c'), 'lvl'=>$lvl, 'msg'=>$msg, 'ctx'=>$ctx];
@file_put_contents($LOG, json_encode($line, JSON_UNESCAPED_SLASHES) . PHP_EOL, FILE_APPEND);
}
function round_price(float $v): float {
// 8 dp is plenty for USD quotes stored in DECIMAL columns
return round($v, 8);
}
function clamp_pct(float $pct, float $min = 0.0, float $max = 90.0): float {
// prevent accidental 1000% etc.
return max($min, min($max, $pct));
}
// ---------- 1) Load target coins (auto_update=1) ----------
$sql = "SELECT UPPER(coin) AS coin, COALESCE(margin_percent,0) AS margin_percent
FROM coin_rates
WHERE auto_update = 1";
$rs = $conn->query($sql);
if (!$rs) {
log_msg('error', 'failed to read coin_rates', ['err' => $conn->error]);
exit(1);
}
$rows = [];
$idsToFetch = []; // set of coingecko slugs
$slugToCoin = []; // slug -> coin symbol
while ($r = $rs->fetch_assoc()) {
$coin = strtoupper($r['coin'] ?? '');
if ($coin === '') continue;
$rows[$coin] = [
'coin' => $coin,
'margin' => (float)$r['margin_percent'], // PERCENT (e.g., 0.5 means 0.5%)
];
if (!isset($COINGECKO_MAP[$coin])) {
log_msg('warn', 'no CoinGecko mapping; skipping', ['coin' => $coin]);
continue;
}
$slug = $COINGECKO_MAP[$coin];
$idsToFetch[$slug] = true;
$slugToCoin[$slug] = $coin;
}
if (empty($idsToFetch)) {
log_msg('info', 'no coins to update (none with auto_update=1 or no mappings)');
exit(0);
}
// ---------- 2) Fetch market prices from CoinGecko ----------
$idsParam = implode(',', array_keys($idsToFetch));
$url = "https://api.coingecko.com/api/v3/simple/price?ids={$idsParam}&vs_currencies=usd";
$resp = @file_get_contents($url);
if ($resp === false) {
log_msg('error', 'failed to fetch CoinGecko', ['url' => $url]);
exit(1);
}
$data = json_decode($resp, true);
if (!is_array($data)) {
log_msg('error', 'invalid CoinGecko JSON', ['snippet' => substr($resp, 0, 200)]);
exit(1);
}
// ---------- 3) Prepare update statement ----------
$upd = $conn->prepare("UPDATE coin_rates SET sell_rate=?, buy_rate=?, updated_at=NOW() WHERE coin=?");
if (!$upd) {
log_msg('error', 'prepare failed', ['err' => $conn->error]);
exit(1);
}
// ---------- 4) Apply percentage margin and write ----------
$updated = 0;
foreach ($slugToCoin as $slug => $coin) {
if (!isset($data[$slug]['usd'])) {
log_msg('warn', 'missing usd price from CoinGecko', ['coin' => $coin, 'slug' => $slug]);
continue;
}
$live = (float)$data[$slug]['usd'];
if ($live <= 0) {
log_msg('warn', 'non-positive live price; skip', ['coin' => $coin, 'live' => $live]);
continue;
}
// margin_percent is percentage of live price
$mPct = clamp_pct((float)$rows[$coin]['margin']); // e.g., 0.50 = 0.5%
$m = $mPct / 100.0;
// Your rules (percentage-based):
// sell_rate = live * (1 + m)
// buy_rate = live * (1 - m)
$sell = $live * (1.0 + $m);
$buy = $live * (1.0 - $m);
// Avoid non-positive buy after extreme margins
if ($buy <= 0) {
$buy = 0.00000001;
}
$sell = round_price($sell);
$buy = round_price($buy);
$upd->bind_param('dds', $sell, $buy, $coin);
if (!$upd->execute()) {
log_msg('error', 'update failed', ['coin' => $coin, 'err' => $upd->error]);
continue;
}
$updated++;
log_msg('info', 'rate updated', [
'coin' => $coin,
'live' => $live,
'margin_percent' => $mPct,
'sell_rate' => $sell,
'buy_rate' => $buy
]);
}
$upd->close();
log_msg('info', 'done', ['updated' => $updated]);
Выполнить команду
Для локальной разработки. Не используйте в интернете!