commit fbcb0d063f3587b91e4d60cc253ac60e343620f1 Author: Ahyan Z Date: Wed Jun 24 21:33:55 2026 +0100 Upload PHP Files diff --git a/NostolgaGram/api/v1/accounts/login.php b/NostolgaGram/api/v1/accounts/login.php new file mode 100644 index 0000000..ff1e5ae --- /dev/null +++ b/NostolgaGram/api/v1/accounts/login.php @@ -0,0 +1,71 @@ + "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; \ No newline at end of file diff --git a/NostolgaGram/api/v1/accounts/register.php b/NostolgaGram/api/v1/accounts/register.php new file mode 100644 index 0000000..4b39661 --- /dev/null +++ b/NostolgaGram/api/v1/accounts/register.php @@ -0,0 +1,71 @@ + "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; \ No newline at end of file diff --git a/NostolgaGram/api/v1/accounts/upload_profile_pic.php b/NostolgaGram/api/v1/accounts/upload_profile_pic.php new file mode 100644 index 0000000..4696094 --- /dev/null +++ b/NostolgaGram/api/v1/accounts/upload_profile_pic.php @@ -0,0 +1,103 @@ + "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; \ No newline at end of file diff --git a/NostolgaGram/api/v1/direct_v2/broadcast.php b/NostolgaGram/api/v1/direct_v2/broadcast.php new file mode 100644 index 0000000..8f121fb --- /dev/null +++ b/NostolgaGram/api/v1/direct_v2/broadcast.php @@ -0,0 +1,69 @@ + "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."])); +} \ No newline at end of file diff --git a/NostolgaGram/api/v1/direct_v2/inbox.php b/NostolgaGram/api/v1/direct_v2/inbox.php new file mode 100644 index 0000000..0fd6e9a --- /dev/null +++ b/NostolgaGram/api/v1/direct_v2/inbox.php @@ -0,0 +1,99 @@ + "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."])); +} \ No newline at end of file diff --git a/NostolgaGram/api/v1/direct_v2/threads.php b/NostolgaGram/api/v1/direct_v2/threads.php new file mode 100644 index 0000000..fc51c55 --- /dev/null +++ b/NostolgaGram/api/v1/direct_v2/threads.php @@ -0,0 +1,74 @@ + "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."])); +} \ No newline at end of file diff --git a/NostolgaGram/api/v1/feed/timeline.php b/NostolgaGram/api/v1/feed/timeline.php new file mode 100644 index 0000000..28c71c8 --- /dev/null +++ b/NostolgaGram/api/v1/feed/timeline.php @@ -0,0 +1,131 @@ + "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."])); +} \ No newline at end of file diff --git a/NostolgaGram/api/v1/media/configure.php b/NostolgaGram/api/v1/media/configure.php new file mode 100644 index 0000000..3b744ff --- /dev/null +++ b/NostolgaGram/api/v1/media/configure.php @@ -0,0 +1,62 @@ + "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; \ No newline at end of file diff --git a/NostolgaGram/api/v1/media/delete.php b/NostolgaGram/api/v1/media/delete.php new file mode 100644 index 0000000..00fe5cb --- /dev/null +++ b/NostolgaGram/api/v1/media/delete.php @@ -0,0 +1,70 @@ + "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."])); +} \ No newline at end of file diff --git a/NostolgaGram/api/v1/media/upload.php b/NostolgaGram/api/v1/media/upload.php new file mode 100644 index 0000000..1716e82 --- /dev/null +++ b/NostolgaGram/api/v1/media/upload.php @@ -0,0 +1,76 @@ + "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; \ No newline at end of file diff --git a/NostolgaGram/api/v1/users/check_email.php b/NostolgaGram/api/v1/users/check_email.php new file mode 100644 index 0000000..3021eaa --- /dev/null +++ b/NostolgaGram/api/v1/users/check_email.php @@ -0,0 +1,20 @@ +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; \ No newline at end of file diff --git a/NostolgaGram/config.php b/NostolgaGram/config.php new file mode 100644 index 0000000..b1f9d6c --- /dev/null +++ b/NostolgaGram/config.php @@ -0,0 +1,62 @@ + 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." + ])); + } +} \ No newline at end of file