fix initial files after test
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
// app/controllers/Emojis.php
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require_once __DIR__.'/../helpers/auth.php';
|
||||
require_once __DIR__.'/../helpers/filters.php';
|
||||
require_once __DIR__.'/../helpers/usage.php';
|
||||
|
||||
// Plan + whitelist
|
||||
$planInfo = resolve_plan();
|
||||
$isPro = $planInfo['pro'];
|
||||
$isWl = $planInfo['whitelist'];
|
||||
$acct = $planInfo['account'];
|
||||
$key = $planInfo['key'];
|
||||
$planName = $isPro ? 'pro' : ($isWl ? 'whitelist' : 'free');
|
||||
|
||||
// Caps
|
||||
$maxLimit = $isPro ? 50 : 20;
|
||||
$maxPages = $isPro ? 20 : 5;
|
||||
if ($isWl) { $maxLimit = 100; $maxPages = 1000; }
|
||||
|
||||
// Params
|
||||
$qParam = trim((string)($_GET['q'] ?? ''));
|
||||
$catParam = trim((string)($_GET['category'] ?? ''));
|
||||
$subParam = trim((string)($_GET['subcategory'] ?? ''));
|
||||
$page = max((int)($_GET['page'] ?? 1), 1);
|
||||
$limit = min(max((int)($_GET['limit'] ?? $maxLimit), 1), $maxLimit);
|
||||
|
||||
// Category map (slugs → labels)
|
||||
$CATEGORY_MAP = [
|
||||
'all'=>'all','smileys'=>'Smileys & Emotion','people'=>'People & Body','animals'=>'Animals & Nature','food'=>'Food & Drink','travel'=>'Travel & Places','activities'=>'Activities','objects'=>'Objects','symbols'=>'Symbols','flags'=>'Flags'
|
||||
];
|
||||
|
||||
$catLabel = '';
|
||||
if ($catParam !== '' && strtolower($catParam) !== 'all') {
|
||||
$catLabel = $CATEGORY_MAP[strtolower($catParam)] ?? $catParam;
|
||||
}
|
||||
$subSlug = $subParam !== '' ? dw_slugify($subParam) : '';
|
||||
|
||||
$q = $qParam; $cat = $catLabel; $sub = $subSlug;
|
||||
|
||||
// Usage (Free counted, Pro/WL unlimited)
|
||||
$limitDaily = $isWl ? null : ($isPro ? null : (int)cfg('free_daily_limit', 50));
|
||||
|
||||
$bucket = bucket_id($key);
|
||||
$ymd = day_key();
|
||||
$usage = usage_load($bucket, $ymd);
|
||||
if ($limitDaily !== null) $usage['limit'] = $limitDaily;
|
||||
|
||||
$signature = sig_query($q, $cat, $sub);
|
||||
$sigKey = $signature.'|p1'; // only page 1 increments
|
||||
$atCap = false;
|
||||
|
||||
if ($limitDaily !== null && $page === 1 && !isset($usage['seen'][$sigKey])) {
|
||||
if ($usage['used'] >= $limitDaily) {
|
||||
$atCap = true;
|
||||
} else {
|
||||
$usage['used'] = (int)$usage['used'] + 1;
|
||||
$usage['seen'][$sigKey] = 1;
|
||||
usage_save($bucket, $ymd, $usage);
|
||||
}
|
||||
}
|
||||
|
||||
if ($page > $maxPages) {
|
||||
echo json_encode(['items'=>[],'page'=>$page,'limit'=>$limit,'total'=>0,'plan'=>$planName,'message'=>'Page limit reached for your plan.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Soft cap
|
||||
if ($atCap) {
|
||||
header('X-Dewemoji-Plan: '.$planName);
|
||||
if ($limitDaily === null) {
|
||||
header('X-RateLimit-Limit: unlimited'); header('X-RateLimit-Remaining: unlimited');
|
||||
} else {
|
||||
header('X-RateLimit-Limit: '.$usage['limit']); header('X-RateLimit-Remaining: 0');
|
||||
}
|
||||
header('X-RateLimit-Reset: '.strtotime('tomorrow 00:00:00 UTC'));
|
||||
echo json_encode([
|
||||
'items'=>[],'page'=>$page,'limit'=>$limit,'total'=>0,'plan'=>$planName,
|
||||
'usage'=>[
|
||||
'used'=>(int)$usage['used'],
|
||||
'limit'=>$limitDaily,
|
||||
'remaining'=> $limitDaily===null ? null : max(0, $limitDaily - (int)$usage['used']),
|
||||
'window'=>'daily',
|
||||
'window_ends_at'=>gmdate('c', strtotime('tomorrow 00:00:00 UTC')),
|
||||
'count_basis'=>'distinct_query'
|
||||
],
|
||||
'message'=>'Daily free limit reached. Upgrade to Pro for unlimited usage.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Load data
|
||||
$DATA_PATHS = [
|
||||
__DIR__.'/../data/emojis.json',
|
||||
__DIR__.'/../../data/emojis.json', // fallback if you keep old path
|
||||
];
|
||||
$json = null;
|
||||
foreach ($DATA_PATHS as $p) { if (is_file($p)) { $json = file_get_contents($p); break; } }
|
||||
if ($json === null) { http_response_code(500); echo json_encode(['error'=>'data_not_found']); exit; }
|
||||
$data = json_decode($json, true) ?: [];
|
||||
$items = $data['emojis'] ?? [];
|
||||
|
||||
// Filter
|
||||
$items = array_values(array_filter($items, function($e) use ($q,$cat,$sub) {
|
||||
if ($cat !== '') {
|
||||
if (dw_slugify($e['category'] ?? '') !== dw_slugify($cat)) return false;
|
||||
}
|
||||
if ($sub !== '') {
|
||||
if (dw_slugify($e['subcategory'] ?? '') !== $sub) return false;
|
||||
}
|
||||
if ($q !== '') {
|
||||
$hay = strtolower(implode(' ', [
|
||||
$e['emoji'] ?? '', $e['name'] ?? '', $e['slug'] ?? '',
|
||||
$e['category'] ?? '', $e['subcategory'] ?? '',
|
||||
implode(' ', $e['keywords_en'] ?? []),
|
||||
implode(' ', $e['keywords_id'] ?? []),
|
||||
implode(' ', $e['aliases'] ?? []),
|
||||
implode(' ', $e['shortcodes'] ?? []),
|
||||
]));
|
||||
foreach (preg_split('/\s+/', strtolower($q)) as $tok) {
|
||||
if ($tok !== '' && strpos($hay, $tok) === false) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
$total = count($items);
|
||||
$offset = ($page - 1) * $limit;
|
||||
$items = array_slice($items, $offset, $limit);
|
||||
|
||||
// Shape + tone
|
||||
$items = array_map(function($raw) use ($planName, $isPro) {
|
||||
$e = filterEmoji($raw, $planName, true);
|
||||
$e['supports_skin_tone'] = dw_supports_skin_tone($raw) || dw_supports_skin_tone($e);
|
||||
$e['skin_tone_modifiers'] = dw_skin_tone_modifiers();
|
||||
if ($e['supports_skin_tone'] && !empty($e['emoji'])) {
|
||||
$base = dw_strip_tone($e['emoji']);
|
||||
if ($base !== '') {
|
||||
$e['emoji_base'] = $base;
|
||||
if ($isPro) { $e['variants'] = dw_build_tone_variants($base); }
|
||||
}
|
||||
}
|
||||
return $e;
|
||||
}, $items);
|
||||
|
||||
// ETag (exclude dynamic usage)
|
||||
$etag = '"'.sha1(json_encode([$page,$limit,$q,$cat,$sub,$planName,$total,$items])).'"';
|
||||
header('ETag: '.$etag);
|
||||
header('Cache-Control: public, max-age=120');
|
||||
if (($_SERVER['HTTP_IF_NONE_MATCH'] ?? '') === $etag) { http_response_code(304); exit; }
|
||||
|
||||
// Rate-limit headers
|
||||
header('X-Dewemoji-Plan: '.$planName);
|
||||
if ($limitDaily === null) {
|
||||
header('X-RateLimit-Limit: unlimited'); header('X-RateLimit-Remaining: unlimited');
|
||||
} else {
|
||||
header('X-RateLimit-Limit: '.$usage['limit']);
|
||||
header('X-RateLimit-Remaining: '.max(0, $usage['limit'] - (int)$usage['used']));
|
||||
}
|
||||
header('X-RateLimit-Reset: '.strtotime('tomorrow 00:00:00 UTC'));
|
||||
|
||||
// Response
|
||||
echo json_encode([
|
||||
'items'=>$items,
|
||||
'page'=>$page,
|
||||
'limit'=>$limit,
|
||||
'total'=>$total,
|
||||
'plan'=>$isPro ? 'pro' : 'free',
|
||||
'usage'=>[
|
||||
'used'=>(int)$usage['used'],
|
||||
'limit'=>$limitDaily,
|
||||
'remaining'=> $limitDaily===null ? null : max(0, $limitDaily - (int)$usage['used']),
|
||||
'window'=>'daily',
|
||||
'window_ends_at'=>gmdate('c', strtotime('tomorrow 00:00:00 UTC')),
|
||||
'count_basis'=>'distinct_query'
|
||||
],
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
// config/env.php — adjust for your server
|
||||
return [
|
||||
'debug' => true,
|
||||
|
||||
'db' => [
|
||||
'dsn' => 'mysql:host=127.0.0.1;dbname=dewepw_emojiapi;charset=utf8mb4',
|
||||
'user' => 'dewepw_emojiapi_admin',
|
||||
'pass' => 'o$NUF(.4AHuV{RzT',
|
||||
],
|
||||
|
||||
// SPA + extension origins
|
||||
'allowed_origins' => [
|
||||
'https://emoji.dewe.pw',
|
||||
'chrome-extension://YOUR_EXTENSION_ID',
|
||||
'http://localhost:5173', // dev
|
||||
],
|
||||
|
||||
// First-party whitelist logic
|
||||
'site_host' => 'emoji.dewe.pw',
|
||||
'frontend_header' => 'web-v1', // your SPA sets: X-Dewemoji-Frontend: web-v1
|
||||
|
||||
// Free daily limit for API (Pro/Whitelist are unlimited)
|
||||
'free_daily_limit' => 50,
|
||||
];
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
// public/index.php — tiny router
|
||||
require __DIR__.'/../app/bootstrap.php';
|
||||
require __DIR__.'/../app/helpers/cors.php';
|
||||
|
||||
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) ?: '/';
|
||||
|
||||
// CORS preflight
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { cors_preflight(); exit; }
|
||||
|
||||
// Routes (v1)
|
||||
if ($path === '/v1/emojis') { require __DIR__.'/../app/controllers/Emojis.php'; exit; }
|
||||
if (preg_match('#^/v1/emoji/([^/]+)$#', $path)) { $_GET['slug'] = urldecode($GLOBALS['matches'][1] ?? $GLOBALS['1'] ?? ''); require __DIR__.'/../app/controllers/Emojis.php'; exit; }
|
||||
if ($path === '/v1/license/activate') { require __DIR__.'/../app/controllers/License.php'; exit; }
|
||||
if ($path === '/v1/license/verify') { require __DIR__.'/../app/controllers/License.php'; exit; }
|
||||
if ($path === '/v1/license/deactivate') { require __DIR__.'/../app/controllers/License.php'; exit; }
|
||||
|
||||
// Health
|
||||
if ($path === '/v1/health') {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode(['ok'=>true,'time'=>gmdate('c')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
http_response_code(404);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode(['error'=>'not_found','path'=>$path]);
|
||||
Reference in New Issue
Block a user