// Purchase code $purchase_code = ""; // Your purchase code, don't give it to anyone. $siteEncryptKey = "468b120cc8e8a78333c8cee1d067fa86749ff92d"; // Your site encrypt key, don't give it to anyone. // =============== Redis: connection info ============== // $redis_host = "127.0.0.1"; $redis_port = 6379; $redis_pass = "331396517"; // nếu Redis có requirepass thì điền $redis_timeout= 1.5; // giây // ============== Optional: PHP sessions =============== // if (!headers_sent()) { ini_set('session.save_handler', 'redis'); $sess_path = "tcp://{$redis_host}:{$redis_port}"; if (!empty($redis_pass)) $sess_path .= "?auth=" . rawurlencode($redis_pass); ini_set('session.save_path', $sess_path); } // ================== Redis bootstrap ================== // /** @var Redis|null $REDIS */ $REDIS = null; if (class_exists('Redis')) { try { $REDIS = new Redis(); $REDIS->connect($redis_host, $redis_port, $redis_timeout); if (!empty($redis_pass)) { $REDIS->auth($redis_pass); } // Chọn DB 0 (có thể thay đổi nếu muốn tách session/cache/log) $REDIS->select(0); } catch (Throwable $e) { error_log("Redis connect error: " . $e->getMessage()); $REDIS = null; } } // ================== Cache primitives ================= // function _json_enc($v) { return json_encode($v, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); } function _json_dec($s){ $x=json_decode($s, true); return (json_last_error()===JSON_ERROR_NONE)?$x:false; } function cache_get($key) { global $REDIS; if (!$REDIS) return false; try { $val = $REDIS->get($key); return $val ? _json_dec($val) : false; } catch (Throwable $e) { return false; } } function cache_set($key, $data, $ttl = 300) { global $REDIS; if (!$REDIS) return false; try { return $REDIS->setEx($key, (int)$ttl, _json_enc($data)); } catch (Throwable $e) { return false; } } function cache_del($key) { global $REDIS; if (!$REDIS) return false; try { $REDIS->del($key); } catch (Throwable $e) {} } // ================= Versioned key system =============== // function _ver_key($ns, $id = null) { return is_null($id) ? "v:{$ns}" : "v:{$ns}:{$id}"; } function cache_ver_get($ns, $id = null) { global $REDIS; if (!$REDIS) return 1; $k = _ver_key($ns, $id); try { $v = $REDIS->get($k); if ($v === false) { $REDIS->set($k, 1); return 1; } return (int)$v ?: 1; } catch (Throwable $e) { return 1; } } function cache_ver_bump($ns, $id = null) { global $REDIS; if (!$REDIS) return true; $k = _ver_key($ns, $id); try { $REDIS->incr($k); } catch (Throwable $e) {} return true; } function vkey($parts = []) { return implode(':', $parts); } // ================== Logging (Streams) ================= // function log_event($event, $data = []) { global $REDIS; if (!$REDIS) return false; $fields = array_merge($data, ['event'=>$event, 'ts'=>time()]); try { $REDIS->xAdd("logs:web", '*', array_map('strval', $fields)); } catch (Throwable $e) {} return true; } // =================== Pub/Sub notify =================== // function notify_user($user_id, $type, $payload = []) { global $REDIS; if (!$REDIS) return false; $message = _json_enc(['type'=>$type, 'uid'=>(int)$user_id, 'data'=>$payload, 'ts'=>time()]); try { $REDIS->publish("notifications:user:{$user_id}", $message); } catch (Throwable $e) {} return true; } // =================== MySQL helpers ==================== // function db_row($sql) { global $sqlConnect; $q = mysqli_query($sqlConnect, $sql); return $q ? mysqli_fetch_assoc($q) : null; } function db_all($sql) { global $sqlConnect; $q = mysqli_query($sqlConnect, $sql); $rows = []; if ($q) while ($r = mysqli_fetch_assoc($q)) $rows[] = $r; return $rows; } // ================== SETTINGS cache ==================== // function get_site_settings() { $ns = 'settings'; $ver = cache_ver_get($ns); $ck = vkey([$ns, "v{$ver}"]); if (($settings = cache_get($ck)) !== false) return $settings; $rows = db_all("SELECT * FROM config"); $settings = []; foreach ($rows as $row) $settings[$row['name']] = $row['value']; cache_set($ck, $settings, 3600); return $settings; } function invalidate_site_settings() { cache_ver_bump('settings'); } // ================= USER PROFILE cache ================= // function get_user_profile($user_id) { $user_id = (int)$user_id; $ns = 'user:profile'; $ver = cache_ver_get($ns, $user_id); $ck = vkey(['user','profile',$user_id,"v{$ver}"]); if (($user = cache_get($ck)) !== false) return $user; $user = db_row("SELECT * FROM users WHERE user_id={$user_id} LIMIT 1"); if ($user) cache_set($ck, $user, 600); return $user; } function invalidate_user_profile($user_id) { cache_ver_bump('user:profile', (int)$user_id); } // ==================== POST cache ====================== // function get_post($post_id) { $post_id = (int)$post_id; $ns = 'post'; $ver = cache_ver_get($ns, $post_id); $ck = vkey(['post',$post_id,"v{$ver}"]); if (($post = cache_get($ck)) !== false) return $post; $post = db_row("SELECT * FROM posts WHERE id={$post_id} LIMIT 1"); if ($post) cache_set($ck, $post, 300); return $post; } function invalidate_post($post_id) { cache_ver_bump('post', (int)$post_id); } // ============== TIMELINE cache ================= // function get_timeline($user_id, $page = 1, $limit = 20) { $user_id = (int)$user_id; $page = max(1, (int)$page); $limit = max(1, (int)$limit); $ns = 'timeline'; $ver = cache_ver_get($ns, $user_id); $ck = vkey([$ns,'home',$user_id,"v{$ver}",'page',$page]); if (($posts = cache_get($ck)) !== false) return $posts; if (function_exists('GetPosts')) { $posts = GetPosts([ 'limit' => $limit, 'publisher_id' => 0, 'page' => $page ]); } else { $offset = ($page - 1) * $limit; $posts = db_all("SELECT * FROM posts ORDER BY id DESC LIMIT {$limit} OFFSET {$offset}"); } cache_set($ck, $posts, 60); return $posts; } function invalidate_timeline_for_user($user_id) { cache_ver_bump('timeline', (int)$user_id); } // ============== COUNTS cache ================= // function get_user_followers_count($user_id) { $user_id = (int)$user_id; $ns = 'user:followers'; $ver = cache_ver_get($ns, $user_id); $ck = vkey(['user','followers',$user_id,"v{$ver}"]); if (($cnt = cache_get($ck)) !== false) return (int)$cnt; $row = db_row("SELECT COUNT(*) AS c FROM followers WHERE user_id={$user_id}"); $cnt = $row ? (int)$row['c'] : 0; cache_set($ck, $cnt, 120); return $cnt; } function invalidate_user_followers($user_id) { cache_ver_bump('user:followers', (int)$user_id); } // ================== LIKE/COMMENT COUNTS ================== // function get_post_stats($post_id) { $post_id = (int)$post_id; $ns = 'post:stats'; $ver = cache_ver_get($ns, $post_id); $ck = vkey(['post','stats',$post_id,"v{$ver}"]); if (($stats = cache_get($ck)) !== false) return $stats; $likes = db_row("SELECT COUNT(*) AS c FROM post_likes WHERE post_id={$post_id}"); $cmts = db_row("SELECT COUNT(*) AS c FROM comments WHERE post_id={$post_id}"); $stats = [ 'likes' => $likes ? (int)$likes['c'] : 0, 'comments' => $cmts ? (int)$cmts['c'] : 0, ]; cache_set($ck, $stats, 60); return $stats; } function invalidate_post_stats($post_id) { cache_ver_bump('post:stats', (int)$post_id); } // ================== NOTIFY (pub/sub hook) ================= // function notify_new_post($author_id, $post_id) { notify_user($author_id, 'new_post', ['post_id'=>(int)$post_id]); } ?>