Upload PHP Files
This commit is contained in:
commit
fbcb0d063f
12 changed files with 908 additions and 0 deletions
71
NostolgaGram/api/v1/accounts/login.php
Normal file
71
NostolgaGram/api/v1/accounts/login.php
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Module A: User Handshake Authentication & Auto-Provisioning Engine (Username Required)
|
||||||
|
* Target Path: htdocs/api/v1/accounts/login.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../../config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Method not allowed."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = getDB();
|
||||||
|
|
||||||
|
// 6.20.2 targets the input explicitly via username parameters for log-ins
|
||||||
|
$usernameInput = trim($_POST['username'] ?? $_POST['login'] ?? '');
|
||||||
|
$password = $_POST['password'] ?? '';
|
||||||
|
|
||||||
|
if (empty($usernameInput) || empty($password)) {
|
||||||
|
http_response_code(400);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Username and password required to log in."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Core Verification Query: Strictly looking up by username namespace
|
||||||
|
$stmt = $db->prepare("SELECT * FROM users WHERE username = ?");
|
||||||
|
$stmt->execute([$usernameInput]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
// 2A. Profile found -> Validate password string match
|
||||||
|
if (!password_verify($password, $user['password_hash'])) {
|
||||||
|
http_response_code(401);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Invalid username or password match."]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 2B. Auto-Creation Gateway: Provision an internal email profile automatically since it wasn't supplied
|
||||||
|
$hashedPassword = password_hash($password, PASSWORD_BCRYPT);
|
||||||
|
$cleanUsername = strtolower(preg_replace('/[^A-Za-z0-9_.]/', '', $usernameInput));
|
||||||
|
$generatedEmail = $cleanUsername . "@nostolgagram.internal";
|
||||||
|
$generatedFullName = ucfirst($cleanUsername) . " (NostolgaGram)";
|
||||||
|
|
||||||
|
try {
|
||||||
|
$insertStmt = $db->prepare("INSERT INTO users (username, email, password_hash, full_name) VALUES (?, ?, ?, ?)");
|
||||||
|
$insertStmt->execute([$cleanUsername, $generatedEmail, $hashedPassword, $generatedFullName]);
|
||||||
|
|
||||||
|
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$db->lastInsertId()]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Dynamic generation profile failed."]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Complete Session Handshake
|
||||||
|
http_response_code(200);
|
||||||
|
header("Set-Cookie: sessionid=nostolga_sess_" . $user['id'] . "; Path=/; HttpOnly");
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
"logged_in_user" => [
|
||||||
|
"pk" => (int)$user['id'],
|
||||||
|
"username" => $user['username'],
|
||||||
|
"email" => $user['email'],
|
||||||
|
"full_name" => $user['full_name'],
|
||||||
|
"profile_pic_url" => $user['profile_pic'] ?? 'https://picsum.photos/150/150',
|
||||||
|
"is_private" => false
|
||||||
|
],
|
||||||
|
"status" => "ok"
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
71
NostolgaGram/api/v1/accounts/register.php
Normal file
71
NostolgaGram/api/v1/accounts/register.php
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Module B: Manual Registration Validation & Ingestion Engine (Email Explicitly Required)
|
||||||
|
* Target Path: htdocs/api/v1/accounts/register.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../../config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Method not allowed."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = getDB();
|
||||||
|
|
||||||
|
// Gather parameter arrays pushed out by the registration wizard forms
|
||||||
|
$email = trim($_POST['email'] ?? '');
|
||||||
|
$username = trim($_POST['username'] ?? '');
|
||||||
|
$password = $_POST['password'] ?? '';
|
||||||
|
$fullName = trim($_POST['first_name'] ?? $_POST['username'] ?? '');
|
||||||
|
|
||||||
|
// Enforce safety constraint: Throw error if email or username inputs are missing
|
||||||
|
if (empty($email) || empty($username) || empty($password)) {
|
||||||
|
http_response_code(400);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "An email, username, and password are required to sign up."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Conflict Prevention: Make sure username or email choices aren't duplicated in the matrix
|
||||||
|
$stmt = $db->prepare("SELECT id, username, email FROM users WHERE username = ? OR email = ?");
|
||||||
|
$stmt->execute([$username, $email]);
|
||||||
|
$conflict = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($conflict) {
|
||||||
|
http_response_code(400);
|
||||||
|
$msg = ($conflict['username'] === $username) ? "That username is occupied." : "That email is already registered.";
|
||||||
|
die(json_encode(["status" => "fail", "message" => $msg]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Commit account parameters to data storage blocks
|
||||||
|
$hashedPassword = password_hash($password, PASSWORD_BCRYPT);
|
||||||
|
$cleanFullName = !empty($fullName) ? $fullName : ucfirst($username) . " (NostolgaGram)";
|
||||||
|
|
||||||
|
$insertStmt = $db->prepare("INSERT INTO users (username, email, password_hash, full_name) VALUES (?, ?, ?, ?)");
|
||||||
|
$insertStmt->execute([$username, $email, $hashedPassword, $cleanFullName]);
|
||||||
|
|
||||||
|
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$db->lastInsertId()]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Critical system allocation error during signup processing."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Authenticate and dispatch session payload configuration
|
||||||
|
http_response_code(200);
|
||||||
|
header("Set-Cookie: sessionid=nostolga_sess_" . $user['id'] . "; Path=/; HttpOnly");
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
"created_user" => [
|
||||||
|
"pk" => (int)$user['id'],
|
||||||
|
"username" => $user['username'],
|
||||||
|
"email" => $user['email'],
|
||||||
|
"full_name" => $user['full_name'],
|
||||||
|
"profile_pic_url" => $user['profile_pic'] ?? 'https://picsum.photos/150/150',
|
||||||
|
"is_private" => false
|
||||||
|
],
|
||||||
|
"status" => "ok"
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
103
NostolgaGram/api/v1/accounts/upload_profile_pic.php
Normal file
103
NostolgaGram/api/v1/accounts/upload_profile_pic.php
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Module C: Profile Picture Ingestion via Unsigned Cloudinary Pipeline
|
||||||
|
* Target Path: htdocs/api/v1/accounts/upload_profile_pic.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Inherit global server variables and database engine
|
||||||
|
require_once __DIR__ . '/../../../config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Method not allowed. Use POST pipeline."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Session Identification Verification
|
||||||
|
// Extract the custom cookie session string sent by the app
|
||||||
|
$sessionCookie = $_COOKIE['sessionid'] ?? '';
|
||||||
|
if (empty($sessionCookie) || strpos($sessionCookie, 'nostolga_sess_') !== 0) {
|
||||||
|
http_response_code(401);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Unauthorized client session context."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the raw primary key ID directly from the trailing string token
|
||||||
|
$userId = (int)str_replace('nostolga_sess_', '', $sessionCookie);
|
||||||
|
|
||||||
|
$db = getDB();
|
||||||
|
|
||||||
|
// 2. Locate the Binary File Array Payload
|
||||||
|
// 2014 Instagram uploads typically label image fields as 'profile_pic' or 'file'
|
||||||
|
$fileKey = isset($_FILES['profile_pic']) ? 'profile_pic' : (isset($_FILES['file']) ? 'file' : null);
|
||||||
|
|
||||||
|
if (!$fileKey || $_FILES[$fileKey]['error'] !== UPLOAD_ERR_OK) {
|
||||||
|
http_response_code(400);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "No valid binary payload detected in file stream."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmpFilePath = $_FILES[$fileKey]['tmp_name'];
|
||||||
|
|
||||||
|
// 3. Handshake and Ship Binary Directly to Cloudinary Engine
|
||||||
|
$cloudinaryUrl = "https://api.cloudinary.com/v1_1/" . CLOUDINARY_CLOUD_NAME . "/image/upload";
|
||||||
|
|
||||||
|
// Create cURL Multipart Payload Fields
|
||||||
|
$payload = [
|
||||||
|
'file' => new CURLFile($tmpFilePath),
|
||||||
|
'upload_preset' => CLOUDINARY_UPLOAD_PRESET
|
||||||
|
];
|
||||||
|
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $cloudinaryUrl);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Crucial for seamless connection processing under InfinityFree hosts
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($httpCode !== 200 || !$response) {
|
||||||
|
http_response_code(502);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Edge CDN ingestion system rejected payload processing."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$responseData = json_decode($response, true);
|
||||||
|
$secureCdnUrl = $responseData['secure_url'] ?? '';
|
||||||
|
|
||||||
|
if (empty($secureCdnUrl)) {
|
||||||
|
http_response_code(502);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Failed to extract valid secure resource asset locator."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 4. Persist Secure Asset Link to the User Database Row
|
||||||
|
$updateStmt = $db->prepare("UPDATE users SET profile_pic = ? WHERE id = ?");
|
||||||
|
$updateStmt->execute([$secureCdnUrl, $userId]);
|
||||||
|
|
||||||
|
// Fetch newly compiled profile state to populate the legacy response payload
|
||||||
|
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$userId]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
http_response_code(404);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Target profile entity reference lost."]));
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Database serialization mapping failed."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Structure legacy data block to update application state variables
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode([
|
||||||
|
"user" => [
|
||||||
|
"pk" => (int)$user['id'],
|
||||||
|
"username" => $user['username'],
|
||||||
|
"full_name" => $user['full_name'],
|
||||||
|
"profile_pic_url" => $user['profile_pic'],
|
||||||
|
"is_private" => false
|
||||||
|
],
|
||||||
|
"status" => "ok"
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
69
NostolgaGram/api/v1/direct_v2/broadcast.php
Normal file
69
NostolgaGram/api/v1/direct_v2/broadcast.php
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Module G3: Outbound DM Broadcasting Post Router
|
||||||
|
* Target Path: htdocs/api/v1/direct_v2/broadcast.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../../config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Method not allowed."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$sessionCookie = $_COOKIE['sessionid'] ?? '';
|
||||||
|
if (empty($sessionCookie) || strpos($sessionCookie, 'nostolga_sess_') !== 0) {
|
||||||
|
http_response_code(401);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Unauthorized session context."]));
|
||||||
|
}
|
||||||
|
$userId = (int)str_replace('nostolga_sess_', '', $sessionCookie);
|
||||||
|
|
||||||
|
// Gather values pushed from the app UI form
|
||||||
|
$text = $_POST['text'] ?? '';
|
||||||
|
$recipientJson = $_POST['recipients'] ?? ''; // App packages recipient IDs inside an explicit JSON format array string
|
||||||
|
|
||||||
|
// Parse target out of the JSON parameter payload
|
||||||
|
$recipientId = 0;
|
||||||
|
if (!empty($recipientJson)) {
|
||||||
|
$recipientsArray = json_decode($recipientJson, true);
|
||||||
|
// Grab the first ID listed inside the array
|
||||||
|
$recipientId = (int)($recipientsArray[0] ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: Check standard direct target params if the array wrapper was bypassed
|
||||||
|
if ($recipientId === 0) {
|
||||||
|
$recipientId = (int)($_POST['recipient_users'] ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($text) || $recipientId === 0) {
|
||||||
|
http_response_code(400);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Required payload message configurations missing."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = getDB();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$timestamp = time();
|
||||||
|
|
||||||
|
// Write message into table matrix ledger
|
||||||
|
$stmt = $db->prepare("INSERT INTO direct_messages (sender_id, recipient_id, message_text, created_at) VALUES (?, ?, ?, ?)");
|
||||||
|
$stmt->execute([$userId, $recipientId, $text, $timestamp]);
|
||||||
|
$newMsgId = $db->lastInsertId();
|
||||||
|
|
||||||
|
// Mirror the broadcast output structure format so it updates instantly in the chat UI screen
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode([
|
||||||
|
"payload" => [
|
||||||
|
"item_id" => (string)$newMsgId,
|
||||||
|
"timestamp" => $timestamp * 1000000,
|
||||||
|
"item_type" => "text",
|
||||||
|
"text" => $text
|
||||||
|
],
|
||||||
|
"status" => "ok"
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Data broadcast recording sequence failed."]));
|
||||||
|
}
|
||||||
99
NostolgaGram/api/v1/direct_v2/inbox.php
Normal file
99
NostolgaGram/api/v1/direct_v2/inbox.php
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Module G1: DM Conversations List Aggregator
|
||||||
|
* Target Path: htdocs/api/v1/direct_v2/inbox.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../../config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||||
|
http_response_code(405);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Method not allowed."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$sessionCookie = $_COOKIE['sessionid'] ?? '';
|
||||||
|
if (empty($sessionCookie) || strpos($sessionCookie, 'nostolga_sess_') !== 0) {
|
||||||
|
http_response_code(401);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Unauthorized session context."]));
|
||||||
|
}
|
||||||
|
$userId = (int)str_replace('nostolga_sess_', '', $sessionCookie);
|
||||||
|
|
||||||
|
$db = getDB();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check for the most recent message exchanged by this user
|
||||||
|
$stmt = $db->prepare("SELECT * FROM direct_messages
|
||||||
|
WHERE sender_id = ? OR recipient_id = ?
|
||||||
|
ORDER BY id DESC LIMIT 1");
|
||||||
|
$stmt->execute([$userId, $userId]);
|
||||||
|
$lastMsg = $stmt->fetch();
|
||||||
|
|
||||||
|
$threads = [];
|
||||||
|
|
||||||
|
if ($lastMsg) {
|
||||||
|
// Active conversation exists -> Determine the opposing chatter's profile
|
||||||
|
$otherUserId = ($lastMsg['sender_id'] == $userId) ? $lastMsg['recipient_id'] : $lastMsg['sender_id'];
|
||||||
|
|
||||||
|
$userStmt = $db->prepare("SELECT id, username, full_name, profile_pic FROM users WHERE id = ?");
|
||||||
|
$userStmt->execute([$otherUserId]);
|
||||||
|
$otherUser = $userStmt->fetch();
|
||||||
|
|
||||||
|
if ($otherUser) {
|
||||||
|
$threads[] = [
|
||||||
|
"thread_id" => "thread_" . $otherUser['id'],
|
||||||
|
"users" => [[
|
||||||
|
"pk" => (int)$otherUser['id'],
|
||||||
|
"username" => $otherUser['username'],
|
||||||
|
"full_name" => $otherUser['full_name'],
|
||||||
|
"profile_pic_url" => $otherUser['profile_pic'] ?? 'https://picsum.photos/150/150'
|
||||||
|
]],
|
||||||
|
"last_activity_at" => (int)$lastMsg['created_at'] * 1000000,
|
||||||
|
"items" => [[
|
||||||
|
"item_id" => (string)$lastMsg['id'],
|
||||||
|
"user_id" => (int)$lastMsg['sender_id'],
|
||||||
|
"timestamp" => (int)$lastMsg['created_at'] * 1000000,
|
||||||
|
"item_type" => "text",
|
||||||
|
"text" => $lastMsg['message_text']
|
||||||
|
]],
|
||||||
|
"canonical" => true,
|
||||||
|
"named" => false
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Fallback welcoming chat thread
|
||||||
|
$threads[] = [
|
||||||
|
"thread_id" => "thread_999",
|
||||||
|
"users" => [[
|
||||||
|
"pk" => 999,
|
||||||
|
"username" => "nostolga_support",
|
||||||
|
"full_name" => "System Direct Engine",
|
||||||
|
"profile_pic_url" => "https://picsum.photos/150/150"
|
||||||
|
]],
|
||||||
|
"last_activity_at" => time() * 1000000,
|
||||||
|
"items" => [[
|
||||||
|
"item_id" => "mock_msg_001",
|
||||||
|
"user_id" => 999,
|
||||||
|
"timestamp" => time() * 1000000,
|
||||||
|
"item_type" => "text",
|
||||||
|
"text" => "Welcome to Direct Messages! Your chat nodes are active. Broadcast a message to test."
|
||||||
|
]],
|
||||||
|
"canonical" => true,
|
||||||
|
"named" => false
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode([
|
||||||
|
"inbox" => [
|
||||||
|
"threads" => $threads,
|
||||||
|
"unseen_count" => 0,
|
||||||
|
"unseen_count_ts" => time() * 1000000
|
||||||
|
],
|
||||||
|
"status" => "ok"
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Inbox matrix retrieval failure."]));
|
||||||
|
}
|
||||||
74
NostolgaGram/api/v1/direct_v2/threads.php
Normal file
74
NostolgaGram/api/v1/direct_v2/threads.php
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Module G2: Target Chat Logs Compilation Matrix
|
||||||
|
* Target Path: htdocs/api/v1/direct_v2/threads.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../../config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||||
|
http_response_code(405);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Method not allowed."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$sessionCookie = $_COOKIE['sessionid'] ?? '';
|
||||||
|
if (empty($sessionCookie) || strpos($sessionCookie, 'nostolga_sess_') !== 0) {
|
||||||
|
http_response_code(401);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Unauthorized session context."]));
|
||||||
|
}
|
||||||
|
$userId = (int)str_replace('nostolga_sess_', '', $sessionCookie);
|
||||||
|
|
||||||
|
// Grab target thread identifier sent through from our htaccess URL variables
|
||||||
|
$rawThreadId = $_GET['thread_id'] ?? '0';
|
||||||
|
$targetRecipientId = (int)str_replace('thread_', '', $rawThreadId);
|
||||||
|
|
||||||
|
$db = getDB();
|
||||||
|
$items = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($targetRecipientId === 999) {
|
||||||
|
// Provide mock history details for system welcome thread
|
||||||
|
$items[] = [
|
||||||
|
"item_id" => "mock_msg_001",
|
||||||
|
"user_id" => 999,
|
||||||
|
"timestamp" => (time() - 60) * 1000000,
|
||||||
|
"item_type" => "text",
|
||||||
|
"text" => "Welcome to Direct Messages! Your chat nodes are active. Broadcast a message to test."
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
// Query database for logs between these two specific identities
|
||||||
|
$stmt = $db->prepare("SELECT * FROM direct_messages
|
||||||
|
WHERE (sender_id = ? AND recipient_id = ?)
|
||||||
|
OR (sender_id = ? AND recipient_id = ?)
|
||||||
|
ORDER BY id DESC LIMIT 50");
|
||||||
|
$stmt->execute([$userId, $targetRecipientId, $targetRecipientId, $userId]);
|
||||||
|
$messages = $stmt->fetchAll();
|
||||||
|
|
||||||
|
foreach ($messages as $msg) {
|
||||||
|
$items[] = [
|
||||||
|
"item_id" => (string)$msg['id'],
|
||||||
|
"user_id" => (int)$msg['sender_id'],
|
||||||
|
"timestamp" => (int)$msg['created_at'] * 1000000,
|
||||||
|
"item_type" => "text",
|
||||||
|
"text" => $msg['message_text']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the container object structure for version 6.20.2 parsing mechanics
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode([
|
||||||
|
"thread" => [
|
||||||
|
"thread_id" => "thread_" . $targetRecipientId,
|
||||||
|
"items" => $items,
|
||||||
|
"more_available" => false,
|
||||||
|
"status" => "ok"
|
||||||
|
],
|
||||||
|
"status" => "ok"
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Thread ledger lookup failure."]));
|
||||||
|
}
|
||||||
131
NostolgaGram/api/v1/feed/timeline.php
Normal file
131
NostolgaGram/api/v1/feed/timeline.php
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Module D: Timeline Feed Compilation Engine (Database Driven)
|
||||||
|
* Target Path: htdocs/api/v1/feed/timeline.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Inherit the universal configuration hub
|
||||||
|
require_once __DIR__ . '/../../../config.php';
|
||||||
|
|
||||||
|
// Instagram 6.20.2 requests timeline data streams using GET
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||||
|
http_response_code(405);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Method not allowed. Use GET query pipeline."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Optional Session Catching (For custom tailored feeds or liking flags later)
|
||||||
|
$sessionCookie = $_COOKIE['sessionid'] ?? '';
|
||||||
|
$currentUserId = 0;
|
||||||
|
if (!empty($sessionCookie) && strpos($sessionCookie, 'nostolga_sess_') === 0) {
|
||||||
|
$currentUserId = (int)str_replace('nostolga_sess_', '', $sessionCookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = getDB();
|
||||||
|
|
||||||
|
try {
|
||||||
|
/**
|
||||||
|
* 2. Pull Live Posts Linked with Creator Profiles
|
||||||
|
*
|
||||||
|
* NOTE: As you expand your database schema, ensure you create a `posts` table containing:
|
||||||
|
* id (INT AUTO_INCREMENT), user_id (INT), media_url (VARCHAR), caption (TEXT), created_at (INT)
|
||||||
|
*
|
||||||
|
* This query falls back gracefully to standard dummy content if your live table is empty.
|
||||||
|
*/
|
||||||
|
$posts = [];
|
||||||
|
|
||||||
|
// Check if the posts table exists in phpMyAdmin before running
|
||||||
|
$tableCheck = $db->query("SHOW TABLES LIKE 'posts'")->rowCount();
|
||||||
|
|
||||||
|
if ($tableCheck > 0) {
|
||||||
|
$query = "SELECT p.*, u.username, u.full_name, u.profile_pic
|
||||||
|
FROM posts p
|
||||||
|
JOIN users u ON p.user_id = u.id
|
||||||
|
ORDER BY p.id DESC LIMIT 30";
|
||||||
|
$stmt = $db->query($query);
|
||||||
|
$posts = $stmt->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
$feedItems = [];
|
||||||
|
|
||||||
|
// 3. Loop through your live data records and structuralize them for Instagram 6.20.2
|
||||||
|
foreach ($posts as $post) {
|
||||||
|
$feedItems[] = [
|
||||||
|
"pk" => (int)$post['id'],
|
||||||
|
"id" => $post['id'] . "_" . $post['user_id'],
|
||||||
|
"device_timestamp" => (int)$post['created_at'],
|
||||||
|
"media_type" => 1, // 1 = Standard Square Photo Image Layout
|
||||||
|
"code" => "post_" . $post['id'],
|
||||||
|
"image_versions2" => [
|
||||||
|
"candidates" => [
|
||||||
|
[
|
||||||
|
"url" => $post['media_url'],
|
||||||
|
"width" => 600,
|
||||||
|
"height" => 600
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"user" => [
|
||||||
|
"pk" => (int)$post['user_id'],
|
||||||
|
"username" => $post['username'],
|
||||||
|
"full_name" => $post['full_name'],
|
||||||
|
"profile_pic_url" => $post['profile_pic'] ?? 'https://picsum.photos/150/150',
|
||||||
|
"is_private" => false
|
||||||
|
],
|
||||||
|
"caption" => [
|
||||||
|
"text" => $post['caption'] ?? '',
|
||||||
|
"created_at" => (int)$post['created_at']
|
||||||
|
],
|
||||||
|
"like_count" => 0, // Expand later via a likes mapping table
|
||||||
|
"has_liked" => false,
|
||||||
|
"comment_count" => 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Fallback Architecture: Show an initial welcome item if your database table is still empty
|
||||||
|
if (empty($feedItems)) {
|
||||||
|
$feedItems[] = [
|
||||||
|
"pk" => 999999999,
|
||||||
|
"id" => "999999999_1",
|
||||||
|
"device_timestamp" => time(),
|
||||||
|
"media_type" => 1,
|
||||||
|
"code" => "welcome_post",
|
||||||
|
"image_versions2" => [
|
||||||
|
"candidates" => [
|
||||||
|
[
|
||||||
|
"url" => "https://res.cloudinary.com/demo/image/upload/c_fill,g_auto,w_600,h_600/sample.jpg",
|
||||||
|
"width" => 600,
|
||||||
|
"height" => 600
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"user" => [
|
||||||
|
"pk" => 1,
|
||||||
|
"username" => "nostolgagram_system",
|
||||||
|
"full_name" => "System Hub Core",
|
||||||
|
"profile_pic_url" => "https://picsum.photos/150/150",
|
||||||
|
"is_private" => false
|
||||||
|
],
|
||||||
|
"caption" => [
|
||||||
|
"text" => "Welcome to NostolgaGram! Your dynamic timeline engine is completely online. Start posting media to fill up your feed!",
|
||||||
|
"created_at" => time()
|
||||||
|
],
|
||||||
|
"like_count" => 1337,
|
||||||
|
"has_liked" => false,
|
||||||
|
"comment_count" => 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Package output matching legacy format structures
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode([
|
||||||
|
"items" => $feedItems,
|
||||||
|
"num_results" => count($feedItems),
|
||||||
|
"more_available" => false,
|
||||||
|
"status" => "ok"
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Feed matrix assembly array sequence dropped."]));
|
||||||
|
}
|
||||||
62
NostolgaGram/api/v1/media/configure.php
Normal file
62
NostolgaGram/api/v1/media/configure.php
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Module E2: Post Caption Configurator & Database Committer
|
||||||
|
* Target Path: htdocs/api/v1/media/configure.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../../config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Method not allowed."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse Session Identity
|
||||||
|
$sessionCookie = $_COOKIE['sessionid'] ?? '';
|
||||||
|
if (empty($sessionCookie) || strpos($sessionCookie, 'nostolga_sess_') !== 0) {
|
||||||
|
http_response_code(401);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Session verification required."]));
|
||||||
|
}
|
||||||
|
$userId = (int)str_replace('nostolga_sess_', '', $sessionCookie);
|
||||||
|
|
||||||
|
$db = getDB();
|
||||||
|
|
||||||
|
// Gather payload configurations
|
||||||
|
$uploadId = $_POST['upload_id'] ?? '';
|
||||||
|
$caption = $_POST['caption_text'] ?? '';
|
||||||
|
|
||||||
|
// Grab the secure URL string cached from our upload script step
|
||||||
|
$cachedUrlCookie = "pending_media_" . $uploadId;
|
||||||
|
$mediaUrl = $_COOKIE[$cachedUrlCookie] ?? '';
|
||||||
|
|
||||||
|
if (empty($mediaUrl)) {
|
||||||
|
http_response_code(400);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Missing media resource locator. Upload session expired."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Write post metadata to the newly generated MySQL table
|
||||||
|
$timestamp = time();
|
||||||
|
$insertStmt = $db->prepare("INSERT INTO posts (user_id, media_url, caption, created_at) VALUES (?, ?, ?, ?)");
|
||||||
|
$insertStmt->execute([$userId, $mediaUrl, $caption, $timestamp]);
|
||||||
|
|
||||||
|
// Clear temporary cache token
|
||||||
|
setcookie($cachedUrlCookie, '', time() - 3600, "/");
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Failed to write post records to data matrix."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Respond back using the expected 2014 object model format so the app exits the upload screens seamlessly
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode([
|
||||||
|
"media" => [
|
||||||
|
"pk" => (int)$db->lastInsertId(),
|
||||||
|
"media_type" => 1,
|
||||||
|
"code" => "post_conf_" . $uploadId,
|
||||||
|
"status" => "ok"
|
||||||
|
],
|
||||||
|
"status" => "ok"
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
70
NostolgaGram/api/v1/media/delete.php
Normal file
70
NostolgaGram/api/v1/media/delete.php
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Module F: Media Elimination Engine
|
||||||
|
* Target Path: htdocs/api/v1/media/delete.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Inherit global variables and database connection instance
|
||||||
|
require_once __DIR__ . '/../../../config.php';
|
||||||
|
|
||||||
|
// Instagram legacy clients send a POST payload request to execute deletions
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Method not allowed. Use POST pipeline."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Session Identity Handshake Verification
|
||||||
|
$sessionCookie = $_COOKIE['sessionid'] ?? '';
|
||||||
|
if (empty($sessionCookie) || strpos($sessionCookie, 'nostolga_sess_') !== 0) {
|
||||||
|
http_response_code(401);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Unauthorized client session context."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode active user primary key ID
|
||||||
|
$userId = (int)str_replace('nostolga_sess_', '', $sessionCookie);
|
||||||
|
|
||||||
|
// 2. Capture the Media ID Passed implicitly from our .htaccess Routing Engine
|
||||||
|
$mediaId = (int)($_GET['media_id'] ?? 0);
|
||||||
|
|
||||||
|
if ($mediaId <= 0) {
|
||||||
|
http_response_code(400);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Invalid target media identifier signature."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = getDB();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 3. Ownership Verification Check
|
||||||
|
// Locate the post to ensure it exists and belongs explicitly to the logged-in user
|
||||||
|
$stmt = $db->prepare("SELECT user_id FROM posts WHERE id = ?");
|
||||||
|
$stmt->execute([$mediaId]);
|
||||||
|
$post = $stmt->fetch();
|
||||||
|
|
||||||
|
if (!$post) {
|
||||||
|
http_response_code(404);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Target media asset registry record not found."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Security Gate: Block malicious deletions from mismatched user accounts
|
||||||
|
if ((int)$post['user_id'] !== $userId) {
|
||||||
|
http_response_code(403);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Access denied. Action signature authorization failure."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Execute the SQL Data Purge
|
||||||
|
// InnoDB cascades or handles deletion cleanly across our constraints
|
||||||
|
$deleteStmt = $db->prepare("DELETE FROM posts WHERE id = ?");
|
||||||
|
$deleteStmt->execute([$mediaId]);
|
||||||
|
|
||||||
|
// 5. Dispatch success payload confirmation back to the app UI matrix
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode([
|
||||||
|
"did_delete" => true,
|
||||||
|
"status" => "ok"
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Database ledger serialization drop encountered during record purge."]));
|
||||||
|
}
|
||||||
76
NostolgaGram/api/v1/media/upload.php
Normal file
76
NostolgaGram/api/v1/media/upload.php
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Module E1: Media Binary Stream Upload Carrier
|
||||||
|
* Target Path: htdocs/api/v1/media/upload.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../../config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Method not allowed."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the client application is authenticated
|
||||||
|
$sessionCookie = $_COOKIE['sessionid'] ?? '';
|
||||||
|
if (empty($sessionCookie) || strpos($sessionCookie, 'nostolga_sess_') !== 0) {
|
||||||
|
http_response_code(401);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Unauthorized session context."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instagram legacy apps look for a unique upload_id to track the processing pipeline
|
||||||
|
// If the client didn't supply one, we auto-generate a timestamp token signature
|
||||||
|
$uploadId = $_POST['upload_id'] ?? (string)floor(microtime(true) * 1000);
|
||||||
|
|
||||||
|
// Detect the file upload array element payload keys
|
||||||
|
$fileKey = isset($_FILES['photo']) ? 'photo' : (isset($_FILES['file']) ? 'file' : null);
|
||||||
|
|
||||||
|
if (!$fileKey || $_FILES[$fileKey]['error'] !== UPLOAD_ERR_OK) {
|
||||||
|
http_response_code(400);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "No valid media binary stream detected."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmpFilePath = $_FILES[$fileKey]['tmp_name'];
|
||||||
|
|
||||||
|
// Handshake with Cloudinary Engine
|
||||||
|
$cloudinaryUrl = "https://api.cloudinary.com/v1_1/" . CLOUDINARY_CLOUD_NAME . "/image/upload";
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
'file' => new CURLFile($tmpFilePath),
|
||||||
|
'upload_preset' => CLOUDINARY_UPLOAD_PRESET
|
||||||
|
];
|
||||||
|
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $cloudinaryUrl);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($httpCode !== 200 || !$response) {
|
||||||
|
http_response_code(502);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "CDN ingestion processing failure."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$responseData = json_decode($response, true);
|
||||||
|
$secureCdnUrl = $responseData['secure_url'] ?? '';
|
||||||
|
|
||||||
|
if (empty($secureCdnUrl)) {
|
||||||
|
http_response_code(502);
|
||||||
|
die(json_encode(["status" => "fail", "message" => "Asset resolution parsing failed."]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since Instagram splits uploading and text configuring into two completely separate actions,
|
||||||
|
// we provision a quick temporary cache cookie to hold the URL string until the configure script fires next.
|
||||||
|
setcookie("pending_media_" . $uploadId, $secureCdnUrl, time() + 300, "/");
|
||||||
|
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode([
|
||||||
|
"upload_id" => $uploadId,
|
||||||
|
"status" => "ok"
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
20
NostolgaGram/api/v1/users/check_email.php
Normal file
20
NostolgaGram/api/v1/users/check_email.php
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Target Path: htdocs/api/v1/users/check_email.php
|
||||||
|
*/
|
||||||
|
require_once __DIR__ . '/../../../config.php';
|
||||||
|
|
||||||
|
$email = trim($_POST['email'] ?? $_GET['email'] ?? '');
|
||||||
|
|
||||||
|
$db = getDB();
|
||||||
|
$stmt = $db->prepare("SELECT id FROM users WHERE email = ?");
|
||||||
|
$stmt->execute([$email]);
|
||||||
|
|
||||||
|
$available = $stmt->fetch() ? false : true;
|
||||||
|
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode([
|
||||||
|
"available" => $available,
|
||||||
|
"status" => "ok"
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
62
NostolgaGram/config.php
Normal file
62
NostolgaGram/config.php
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* NostolgaGram Configuration Hub v1.0
|
||||||
|
* Architecture: InfinityFree Core Matrix + Cloudinary CDN Processing
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 1. Universal Security and Client Handshake Headers
|
||||||
|
// Crucial for allowing old Android clients to connect without CORS errors
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, DELETE");
|
||||||
|
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
|
||||||
|
|
||||||
|
// Handle preflight OPTIONS requests instantly before they reach feature files
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||||
|
http_response_code(200);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Database Connectivity Profiles
|
||||||
|
// Swap these placeholders with your actual keys from your InfinityFree Client Area
|
||||||
|
define('DB_HOST', 'sql112.infinityfree.com');
|
||||||
|
define('DB_USER', 'if0_42261255');
|
||||||
|
define('DB_PASS', '8d1WbfEonq');
|
||||||
|
define('DB_NAME', 'if0_42261255_nostolgagram');
|
||||||
|
|
||||||
|
// 3. Cloudinary Edge CDN Credentials
|
||||||
|
// Swap with your actual cloud account name. The preset matches your unsigned configuration.
|
||||||
|
define('CLOUDINARY_CLOUD_NAME', 'dnkm8pijh');
|
||||||
|
define('CLOUDINARY_UPLOAD_PRESET', 'nostolgagram');
|
||||||
|
|
||||||
|
// 4. Global Managed Database Connection Gateway (PDO)
|
||||||
|
// This function can be safely executed by any file in your directory tree.
|
||||||
|
function getDB() {
|
||||||
|
static $dbInstance = null;
|
||||||
|
|
||||||
|
// Reuse existing connection if already established during the request lifecycle
|
||||||
|
if ($dbInstance !== null) {
|
||||||
|
return $dbInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$dbInstance = new PDO(
|
||||||
|
"mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4",
|
||||||
|
DB_USER,
|
||||||
|
DB_PASS,
|
||||||
|
[
|
||||||
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||||
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||||
|
PDO::ATTR_EMULATE_PREPARES => false,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return $dbInstance;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// Return structured JSON instead of raw PHP syntax blocks if the database drops
|
||||||
|
http_response_code(500);
|
||||||
|
die(json_encode([
|
||||||
|
"status" => "fail",
|
||||||
|
"message" => "Database node offline."
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue