From 58adecb1f7e7ce62650115efcf5eed4ecf2543f5 Mon Sep 17 00:00:00 2001 From: Richard Hong Date: Tue, 3 Dec 2024 13:18:46 -0600 Subject: [PATCH 01/12] updating config example to include new vars that will be called within db.php to connect to mysql siteground database, adding relevant files to register and login with connected db, adding mock response within ftp_upload --- final/config.php.example | 4 +++ final/db.php | 15 +++++++++++ final/ftp_upload.php | 32 ++++++++++++++++++++++ final/index.php | 52 ++++++++++++++++++++++++++++------- final/js/app.js | 26 +++++++++++++----- final/register.php | 58 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 171 insertions(+), 16 deletions(-) create mode 100644 final/db.php create mode 100644 final/register.php diff --git a/final/config.php.example b/final/config.php.example index ae8ba12..720388b 100644 --- a/final/config.php.example +++ b/final/config.php.example @@ -5,6 +5,10 @@ return [ 'ftp_pass' => "FTP_PASS", 'ftp_port' => "21", 'ftp_domain' => 'FTP_DOMAIN', + 'db_host' => 'DB_HOST', + 'db_user' => 'DB_USER', + 'db_pwd' => 'DB_PWD', + 'db_name' => 'DB_NAME', 'api_key' => 'API_KEY', 'api_secret' => 'API_SECRET' ]; \ No newline at end of file diff --git a/final/db.php b/final/db.php new file mode 100644 index 0000000..291bbdf --- /dev/null +++ b/final/db.php @@ -0,0 +1,15 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } catch (PDOException $e) { + die("Connection failed: " . $e->getMessage()); + } +?> diff --git a/final/ftp_upload.php b/final/ftp_upload.php index 50abe21..f8bc671 100644 --- a/final/ftp_upload.php +++ b/final/ftp_upload.php @@ -48,6 +48,36 @@ if (ftp_put($ftp_conn, $remote_file, $file, FTP_BINARY)) { $debug[] = "File uploaded successfully to: $remote_file"; + // Step 4: Mock API Response + // $mock_api_response = [ + // 'result' => [ + // 'tags' => [ + // ['confidence' => 72.304817199707, 'tag' => ['en' => 'star']], + // ['confidence' => 67.556610107422, 'tag' => ['en' => 'sun']], + // ['confidence' => 60.43567276001, 'tag' => ['en' => 'celestial body']], + // ['confidence' => 43.794635772705, 'tag' => ['en' => 'sky']], + // ['confidence' => 41.704250335693, 'tag' => ['en' => 'landscape']], + // // add more tags as needed for testing + // ] + // ], + // 'status' => ['text' => 'success'] + // ]; + + // // Convert to JSON response, simulating a real API response + // $response = json_encode($mock_api_response); + // $debug[] = "Mock API response used for file: $file_url"; + + // // Process the mocked API response + // if ($response) { + // $debug[] = "API call successful for file: $file_url"; + // $data = json_decode($response, true); + // } else { + // $debug[] = "API call failed"; + // echo json_encode(['message' => 'API call failed', 'debug' => $debug]); + // ftp_close($ftp_conn); + // exit; + // } + // Step 4: Call API with FTP file URL $file_url = $config['ftp_domain'] . "/uploads/" . urlencode($file_name); $api_key = $config['api_key']; @@ -65,6 +95,7 @@ if ($response) { $debug[] = "API call successful for file: $file_url"; $data = json_decode($response, true); + $debug[] = "API Response Data: " . print_r($data, true); } else { $debug[] = "API call failed: $curl_error"; echo json_encode(['message' => 'API call failed', 'debug' => $debug]); @@ -99,6 +130,7 @@ 'message' => 'File and metadata uploaded successfully', 'tags' => $tags, 'description' => $description, + 'debug' => $debug ]); } else { $debug[] = "Failed to remotely upload metadata file to: $remote_file"; diff --git a/final/index.php b/final/index.php index 7e0f79f..d2d5e2f 100644 --- a/final/index.php +++ b/final/index.php @@ -1,9 +1,9 @@ @@ -15,20 +15,52 @@
Image Tagging App
-
+

Login

-

+

- - + prepare("SELECT * FROM users WHERE email = :email"); + $stmt->bindParam(':email', $email); + $stmt->execute(); + $user = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($user && password_verify($password, $user['password'])) { + $_SESSION['user_id'] = $user['id']; + $_SESSION['username'] = $user['username']; + $_SESSION['logged_in'] = true; + header('Location: main.php'); + exit; + } else { + echo "Invalid email or password."; + } + } catch (PDOException $e) { + echo "Error: " . $e->getMessage(); + } + } + ?> + + +
- + diff --git a/final/js/app.js b/final/js/app.js index 351273a..1cfb516 100644 --- a/final/js/app.js +++ b/final/js/app.js @@ -168,9 +168,6 @@ function processImage() { form.appendChild(downloadButton); tagsContainer.appendChild(form); } - - // Log data to console - console.log("Response Data:", data); }) .catch((error) => { progress.style.display = "none"; @@ -189,20 +186,37 @@ function downloadImage() { .then((response) => { if (!response.ok) { return response.text().then((text) => { - throw new Error(text); + // Log the raw response text to see any server-side error message + throw new Error(`Server error: ${text}`); + }); + } + // Check if the response is a valid blob (i.e., it contains image data) + if (response.headers.get("Content-Type").includes("image")) { + return response.blob(); // Proceed to retrieve the image blob + } else { + // Handle the case where the server does not return an image + return response.text().then((text) => { + throw new Error(`Unexpected response: ${text}`); }); } - return response.blob(); }) .then((blob) => { + if (!blob || blob.size === 0) { + throw new Error( + "The downloaded file is empty. Check server-side processing." + ); + } + // Create a link to download the file const url = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; - a.download = "modified_image.jpg"; + a.download = "modified_image.jpg"; // Adjust filename as needed document.body.appendChild(a); a.click(); a.remove(); + // Release the object URL after download + window.URL.revokeObjectURL(url); }) .catch((error) => { console.error("Error:", error); diff --git a/final/register.php b/final/register.php new file mode 100644 index 0000000..4bcc1e1 --- /dev/null +++ b/final/register.php @@ -0,0 +1,58 @@ + + + + + Register + + + +
Image Tagging App
+
+
+

Register

+ prepare("INSERT INTO users (username, email, password) VALUES (:username, :email, :password)"); + $stmt->bindParam(':username', $username); + $stmt->bindParam(':email', $email); + $stmt->bindParam(':password', $password); + $stmt->execute(); + + echo "Registration successful!"; + } catch (PDOException $e) { + if ($e->getCode() == 23000) { + echo "Username or email already exists."; + } else { + echo "Error: " . $e->getMessage(); + } + } + } + ?> + + + + + + + + + + + +
+
+ + + From 9138598fff4d0f3d2c5d063d28f51e9967baedf4 Mon Sep 17 00:00:00 2001 From: Richard Hong Date: Tue, 3 Dec 2024 13:20:48 -0600 Subject: [PATCH 02/12] removing unnecessary commentary of mock response logic --- final/ftp_upload.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/final/ftp_upload.php b/final/ftp_upload.php index f8bc671..1a1c9e4 100644 --- a/final/ftp_upload.php +++ b/final/ftp_upload.php @@ -57,17 +57,14 @@ // ['confidence' => 60.43567276001, 'tag' => ['en' => 'celestial body']], // ['confidence' => 43.794635772705, 'tag' => ['en' => 'sky']], // ['confidence' => 41.704250335693, 'tag' => ['en' => 'landscape']], - // // add more tags as needed for testing // ] // ], // 'status' => ['text' => 'success'] // ]; - // // Convert to JSON response, simulating a real API response // $response = json_encode($mock_api_response); // $debug[] = "Mock API response used for file: $file_url"; - // // Process the mocked API response // if ($response) { // $debug[] = "API call successful for file: $file_url"; // $data = json_decode($response, true); From 162252dde9562560e64acdb51ed37a923c9dcd0c Mon Sep 17 00:00:00 2001 From: Richard Hong Date: Tue, 3 Dec 2024 13:22:37 -0600 Subject: [PATCH 03/12] resetting downloadImage function within app.js to original copy, will debug if necessary later --- final/js/app.js | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/final/js/app.js b/final/js/app.js index 1cfb516..351273a 100644 --- a/final/js/app.js +++ b/final/js/app.js @@ -168,6 +168,9 @@ function processImage() { form.appendChild(downloadButton); tagsContainer.appendChild(form); } + + // Log data to console + console.log("Response Data:", data); }) .catch((error) => { progress.style.display = "none"; @@ -186,37 +189,20 @@ function downloadImage() { .then((response) => { if (!response.ok) { return response.text().then((text) => { - // Log the raw response text to see any server-side error message - throw new Error(`Server error: ${text}`); - }); - } - // Check if the response is a valid blob (i.e., it contains image data) - if (response.headers.get("Content-Type").includes("image")) { - return response.blob(); // Proceed to retrieve the image blob - } else { - // Handle the case where the server does not return an image - return response.text().then((text) => { - throw new Error(`Unexpected response: ${text}`); + throw new Error(text); }); } + return response.blob(); }) .then((blob) => { - if (!blob || blob.size === 0) { - throw new Error( - "The downloaded file is empty. Check server-side processing." - ); - } - // Create a link to download the file const url = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; - a.download = "modified_image.jpg"; // Adjust filename as needed + a.download = "modified_image.jpg"; document.body.appendChild(a); a.click(); a.remove(); - // Release the object URL after download - window.URL.revokeObjectURL(url); }) .catch((error) => { console.error("Error:", error); From dbe4c06bb18ad0e389a2a9763c9a8750ccf6e0b9 Mon Sep 17 00:00:00 2001 From: Richard Hong Date: Tue, 3 Dec 2024 13:24:28 -0600 Subject: [PATCH 04/12] reverting back to original error messaging within index.php --- final/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/final/index.php b/final/index.php index d2d5e2f..986e00d 100644 --- a/final/index.php +++ b/final/index.php @@ -18,7 +18,7 @@

Login

-

+

Date: Tue, 3 Dec 2024 13:25:58 -0600 Subject: [PATCH 05/12] removing extraneous debug message used to help construct mock api response data --- final/ftp_upload.php | 1 - 1 file changed, 1 deletion(-) diff --git a/final/ftp_upload.php b/final/ftp_upload.php index 1a1c9e4..e753151 100644 --- a/final/ftp_upload.php +++ b/final/ftp_upload.php @@ -92,7 +92,6 @@ if ($response) { $debug[] = "API call successful for file: $file_url"; $data = json_decode($response, true); - $debug[] = "API Response Data: " . print_r($data, true); } else { $debug[] = "API call failed: $curl_error"; echo json_encode(['message' => 'API call failed', 'debug' => $debug]); From 9d6c819170408aee6e2460802ddae5e5a69dadbd Mon Sep 17 00:00:00 2001 From: Richard Hong Date: Fri, 6 Dec 2024 18:10:56 -0600 Subject: [PATCH 06/12] fixing ftp_upload to handle api calls that yield no tags at all or no tags that meet threshold, updating app.js to account for logic of non-existent tags and fixing downloadImage function to only use tags that are actively checked, updating main.php to show welcome message for logged in username, adding in display_metadata.php for now to test which metadata is able to be retrieved (so far only comments of the embed_metadata.php display) --- final/display_metadata.php | 114 +++++++++++++++++++++++++++++++++++++ final/embed_metadata.php | 112 ++++++++++++++++++++---------------- final/ftp_upload.php | 66 ++++++++++++++------- final/js/app.js | 49 +++++++++------- final/main.php | 5 ++ 5 files changed, 256 insertions(+), 90 deletions(-) create mode 100644 final/display_metadata.php diff --git a/final/display_metadata.php b/final/display_metadata.php new file mode 100644 index 0000000..8947a49 --- /dev/null +++ b/final/display_metadata.php @@ -0,0 +1,114 @@ + + + + + + Image Metadata + + + + +

Image Metadata

+ + +"; + +} else { + echo "

Imagick is not installed or not enabled.

"; +} +?> diff --git a/final/embed_metadata.php b/final/embed_metadata.php index 4be897e..16bbcf4 100644 --- a/final/embed_metadata.php +++ b/final/embed_metadata.php @@ -1,58 +1,70 @@ setImageProperty('exif:ImageDescription', $tags_string); - - // Output the image - header('Content-Type: ' . $image_type); - header('Content-Disposition: attachment; filename="modified_image.' . strtolower($imagick->getImageFormat()) . '"'); - echo $imagick->getImagesBlob(); - - // Clean up - $imagick->clear(); - $imagick->destroy(); - unlink($image_path); - unset($_SESSION['image_path']); - unset($_SESSION['image_type']); -} catch (Exception $e) { - // Clean up - if (isset($imagick)) { - $imagick->clear(); - $imagick->destroy(); - } - if (file_exists($image_path)) { - unlink($image_path); - } - unset($_SESSION['image_path']); - unset($_SESSION['image_type']); + // Download the remote image to a temporary local file + $temp_image_path = sys_get_temp_dir() . '/' . basename($file_url); + $image_data = file_get_contents($file_url); + if ($image_data === false) { + throw new Exception('Failed to download the remote image file.'); + } + file_put_contents($temp_image_path, $image_data); + + // Load the image using Imagick + $imagick = new Imagick($temp_image_path); + + // Embed the selected tags into the image metadata + $tags_string = implode(', ', $selected_tags); + $imagick->setImageProperty('exif:ImageDescription', $tags_string); + $imagick->setImageProperty('exif:Artist', $_SESSION['username']); + $imagick->setImageProperty('comment', $tags_string); - // Log the error - error_log('Error in embed_metadata.php: ' . $e->getMessage()); + // Debug: Output all properties + foreach ($imagick->getImageProperties() as $key => $value) { + error_log("Key: $key, Value: $value"); + } - // Display error in debug window - echo 'Error processing image: ' . htmlspecialchars($e->getMessage()); -} -?> + // Set output format + $imagick->setImageFormat('jpeg'); + + // Save to a temporary output file + $temp_output_path = sys_get_temp_dir() . '/output_image.jpg'; + $imagick->writeImage($temp_output_path); + + // Output the image to the client + $image_type = mime_content_type($temp_output_path); + header('Content-Type: ' . $image_type); + header('Content-Disposition: attachment; filename="modified_image.jpg"'); + readfile($temp_output_path); + + // Clean up + unlink($temp_output_path); + + } catch (Exception $e) { + // Handle errors + if (isset($imagick)) { + $imagick->clear(); + $imagick->destroy(); + } + if (isset($temp_image_path) && file_exists($temp_image_path)) { + unlink($temp_image_path); + } + echo 'Error processing image: ' . htmlspecialchars($e->getMessage()); + } +?> \ No newline at end of file diff --git a/final/ftp_upload.php b/final/ftp_upload.php index e753151..00508c9 100644 --- a/final/ftp_upload.php +++ b/final/ftp_upload.php @@ -47,6 +47,7 @@ // Step 3: Upload the file if (ftp_put($ftp_conn, $remote_file, $file, FTP_BINARY)) { $debug[] = "File uploaded successfully to: $remote_file"; + $file_url = $config['ftp_domain'] . "/uploads/" . urlencode($file_name); // Step 4: Mock API Response // $mock_api_response = [ @@ -76,7 +77,6 @@ // } // Step 4: Call API with FTP file URL - $file_url = $config['ftp_domain'] . "/uploads/" . urlencode($file_name); $api_key = $config['api_key']; $api_secret = $config['api_secret']; @@ -100,7 +100,8 @@ } // Step 5: Write metadata based on API response - if (isset($data['result']['tags'])) { + if (isset($data['result']['tags']) && count($data['result']['tags']) > 0) { + $tags = []; foreach ($data['result']['tags'] as $tag) { if ($tag['confidence'] >= $threshold) { $tags[] = [ @@ -110,34 +111,57 @@ } } - $description = implode(", ", $tags); - $metadata_content = "Image Description: " . $description . "\nUploaded File Name: " . $file_name; - - $remote_file = "uploads/" . pathinfo($file_name, PATHINFO_FILENAME) . "_metadata.txt"; - $local_upload = './uploads/'; - $metadata_file = $local_upload . pathinfo($file_name, PATHINFO_FILENAME) . "_metadata.txt"; + if (count($tags) > 0) { + // Prepare the description from valid tags + $tag_names = array_map(function ($tag) { + return $tag['tag']; + }, $tags); + $description = implode(", ", $tag_names); - if (file_put_contents($metadata_file, $metadata_content) !== false) { - $debug[] = "Metadata file created successfully locally at: " . $metadata_file; - - if (ftp_put($ftp_conn, $remote_file, $metadata_file, FTP_ASCII)) { - $debug[] = "Metadata file uploaded successfully remotely to: $remote_file, deleting local copy"; + // Create metadata content + $metadata_content = "Image Description: " . $description . "\nUploaded File Name: " . $file_name; + + // Prepare metadata file paths + $remote_file = "uploads/" . pathinfo($file_name, PATHINFO_FILENAME) . "_metadata.txt"; + $local_upload = './uploads/'; + $metadata_file = $local_upload . pathinfo($file_name, PATHINFO_FILENAME) . "_metadata.txt"; + + // Write metadata content to local file + if (file_put_contents($metadata_file, $metadata_content) !== false) { + $debug[] = "Metadata file created successfully locally at: " . $metadata_file; + + // Upload metadata file to FTP server + if (ftp_put($ftp_conn, $remote_file, $metadata_file, FTP_ASCII)) { + $debug[] = "Metadata file uploaded successfully remotely to: $remote_file, deleting local copy"; + $_SESSION['image_path'] = $file_url; + echo json_encode([ + 'message' => 'File and metadata uploaded successfully', + 'tags' => $tags, + 'description' => $description, + 'debug' => $debug + ]); + } else { + $debug[] = "Failed to remotely upload metadata file to: $remote_file"; + echo json_encode(['message' => 'Failed to upload metadata file', 'debug' => $debug]); + } + } else { + $debug[] = "Failed to create metadata file."; echo json_encode([ - 'message' => 'File and metadata uploaded successfully', - 'tags' => $tags, - 'description' => $description, + 'message' => 'Failed to create metadata file.', 'debug' => $debug ]); - } else { - $debug[] = "Failed to remotely upload metadata file to: $remote_file"; - echo json_encode(['message' => 'Failed to upload metadata file', 'debug' => $debug]); } } else { - $debug[] = "Failed to create metadata file."; + // Case when no tags meet the threshold + $firstTagConfidence = floor($data['result']['tags'][0]['confidence']); + $debug[] = "No tags found that meet the threshold of $threshold%"; + $debug[] = "Minimum confidence score of $firstTagConfidence is needed to yield results."; echo json_encode([ - 'message' => 'Failed to create metadata file.', + 'message' => 'No tags met the threshold value.', 'debug' => $debug ]); + ftp_close($ftp_conn); + exit; } } else { $debug[] = "No tags found in API response."; diff --git a/final/js/app.js b/final/js/app.js index 351273a..b1f2c7a 100644 --- a/final/js/app.js +++ b/final/js/app.js @@ -110,7 +110,7 @@ function processImage() { formData.append("imageUrl", imageUrl); } - fetch("process_image.php", { method: "POST", body: formData }) + fetch("ftp_upload.php", { method: "POST", body: formData }) .then((response) => response.json()) .then((data) => { // Hide progress indicator @@ -141,23 +141,26 @@ function processImage() { const ul = document.createElement("ul"); ul.className = "tag-list"; - data.tags.forEach((tag) => { - const li = document.createElement("li"); - const checkbox = document.createElement("input"); - checkbox.type = "checkbox"; - checkbox.name = "tags[]"; - checkbox.value = tag.tag; - checkbox.checked = true; - - const label = document.createElement("label"); - label.textContent = `${tag.tag} (Confidence: ${tag.confidence.toFixed( - 2 - )}%)`; - - li.appendChild(checkbox); - li.appendChild(label); - ul.appendChild(li); - }); + if (data.tags && data.tags.length > 0) { + // Process tags only if there are any + data.tags.forEach((tag) => { + const li = document.createElement("li"); + const checkbox = document.createElement("input"); + checkbox.type = "checkbox"; + checkbox.name = "tags[]"; + checkbox.value = tag.tag; + checkbox.checked = true; + + const label = document.createElement("label"); + label.textContent = `${ + tag.tag + } (Confidence: ${tag.confidence.toFixed(2)}%)`; + + li.appendChild(checkbox); + li.appendChild(label); + ul.appendChild(li); + }); + } const downloadButton = document.createElement("button"); downloadButton.type = "button"; @@ -183,7 +186,15 @@ function processImage() { function downloadImage() { const form = document.getElementById("tagsForm"); - const formData = new FormData(form); + const checkedTags = [ + ...form.querySelectorAll('input[name="tags[]"]:checked'), + ]; + + // Create a new FormData object with only the checked tags + const formData = new FormData(); + checkedTags.forEach((checkbox) => { + formData.append("tags[]", checkbox.value); + }); fetch("embed_metadata.php", { method: "POST", body: formData }) .then((response) => { diff --git a/final/main.php b/final/main.php index 9c31ab9..4876fab 100644 --- a/final/main.php +++ b/final/main.php @@ -18,6 +18,11 @@ Logout
+ Welcome, " . htmlspecialchars($_SESSION['username']) . "."; + } + ?>

Process Image

From 0005e32e19d0a310facb494f61c432e015d37d79 Mon Sep 17 00:00:00 2001 From: Richard Hong Date: Fri, 6 Dec 2024 21:34:16 -0600 Subject: [PATCH 07/12] cleaning up code commentary --- final/display_metadata.php | 62 +++++++++++++++++--------------------- final/embed_metadata.php | 9 +++--- 2 files changed, 31 insertions(+), 40 deletions(-) diff --git a/final/display_metadata.php b/final/display_metadata.php index 8947a49..72c4c48 100644 --- a/final/display_metadata.php +++ b/final/display_metadata.php @@ -1,5 +1,4 @@ @@ -52,56 +51,49 @@

=== Image Metadata ===

"; try { - // Create an Imagick object from an image file (replace with the actual image path) - $image = new Imagick('/Users/rhong/Downloads/modified_image.JPG'); // Replace with your image path + $image = new Imagick('/Users/rhong/Downloads/modified_image.JPG'); - // Get all properties (metadata) of the image $properties = $image->getImageProperties(); - // Categorize and group properties $categories = [ - 'EXIF' => [], - 'JPEG' => [], - 'IPTC' => [], - 'XMP' => [], - 'Other' => [] + 'EXIF' => [], + 'JPEG' => [], + 'IPTC' => [], + 'XMP' => [], + 'Other' => [] ]; // Loop through all properties and categorize them foreach ($properties as $key => $value) { - if (strpos($key, 'exif:') === 0) { - $categories['EXIF'][$key] = $value; - } elseif (strpos($key, 'jpeg:') === 0) { - $categories['JPEG'][$key] = $value; - } elseif (strpos($key, 'iptc:') === 0) { - $categories['IPTC'][$key] = $value; - } elseif (strpos($key, 'xmp:') === 0) { - $categories['XMP'][$key] = $value; - } else { - $categories['Other'][$key] = $value; - } + if (strpos($key, 'exif:') === 0) { + $categories['EXIF'][$key] = $value; + } elseif (strpos($key, 'jpeg:') === 0) { + $categories['JPEG'][$key] = $value; + } elseif (strpos($key, 'iptc:') === 0) { + $categories['IPTC'][$key] = $value; + } elseif (strpos($key, 'xmp:') === 0) { + $categories['XMP'][$key] = $value; + } else { + $categories['Other'][$key] = $value; + } } - // Display each category with a heading and better formatting foreach ($categories as $category => $properties) { - if (!empty($properties)) { - echo "
$category Metadata
"; - echo ""; - - foreach ($properties as $key => $value) { - // Enhance readability with indentation and label formatting - $formatted_key = ucfirst(str_replace(['exif:', 'jpeg:', 'iptc:', 'xmp:'], '', $key)); // Clean up the prefix - echo ""; - } + if (!empty($properties)) { + echo "
$category Metadata
"; + echo "
PropertyValue
$formatted_key$value
"; - echo "
PropertyValue
"; + foreach ($properties as $key => $value) { + $formatted_key = ucfirst(str_replace(['exif:', 'jpeg:', 'iptc:', 'xmp:'], '', $key)); + echo "$formatted_key$value"; } - } - // Clean up the image object + echo ""; + } + } $image->destroy(); } catch (Exception $e) { - echo "

Error using Imagick: " . $e->getMessage() . "

"; + echo "

Error using Imagick: " . $e->getMessage() . "

"; } echo "
diff --git a/final/embed_metadata.php b/final/embed_metadata.php index 16bbcf4..7ac6fdd 100644 --- a/final/embed_metadata.php +++ b/final/embed_metadata.php @@ -22,7 +22,7 @@ $temp_image_path = sys_get_temp_dir() . '/' . basename($file_url); $image_data = file_get_contents($file_url); if ($image_data === false) { - throw new Exception('Failed to download the remote image file.'); + throw new Exception('Failed to download the remote image file.'); } file_put_contents($temp_image_path, $image_data); @@ -57,13 +57,12 @@ unlink($temp_output_path); } catch (Exception $e) { - // Handle errors if (isset($imagick)) { - $imagick->clear(); - $imagick->destroy(); + $imagick->destroy(); + $imagick->clear(); } if (isset($temp_image_path) && file_exists($temp_image_path)) { - unlink($temp_image_path); + unlink($temp_image_path); } echo 'Error processing image: ' . htmlspecialchars($e->getMessage()); } From 02137b255a6737f7815c2f0dba50a20a53bcc57d Mon Sep 17 00:00:00 2001 From: Richard Hong Date: Sat, 7 Dec 2024 10:40:26 -0600 Subject: [PATCH 08/12] switching to mock api call within ftp_upload, changing styling and ordering of checkboxes with labels to have within same horizontal row --- final/css/style.css | 12 +++++-- final/ftp_upload.php | 78 ++++++++++++++++++++++---------------------- final/js/app.js | 2 +- 3 files changed, 49 insertions(+), 43 deletions(-) diff --git a/final/css/style.css b/final/css/style.css index bd7f321..86e8a23 100644 --- a/final/css/style.css +++ b/final/css/style.css @@ -25,13 +25,16 @@ form { padding: 20px; border-radius: 5px; } -label, input, button { +label, +input, +button { display: block; width: 100%; margin-bottom: 10px; color: #ffffff; } -input, button { +input, +button { padding: 10px; background-color: #333333; border: none; @@ -57,7 +60,8 @@ button { margin: 0 auto; } @keyframes bounce { - 0%, 100% { + 0%, + 100% { transform: translateY(0); } 50% { @@ -80,6 +84,8 @@ button { } .tag-list li { margin-bottom: 5px; + display: flex; + justify-content: space-between; } #drop-area { border: 2px dashed #ffffff; diff --git a/final/ftp_upload.php b/final/ftp_upload.php index 00508c9..e2e1ded 100644 --- a/final/ftp_upload.php +++ b/final/ftp_upload.php @@ -50,55 +50,55 @@ $file_url = $config['ftp_domain'] . "/uploads/" . urlencode($file_name); // Step 4: Mock API Response - // $mock_api_response = [ - // 'result' => [ - // 'tags' => [ - // ['confidence' => 72.304817199707, 'tag' => ['en' => 'star']], - // ['confidence' => 67.556610107422, 'tag' => ['en' => 'sun']], - // ['confidence' => 60.43567276001, 'tag' => ['en' => 'celestial body']], - // ['confidence' => 43.794635772705, 'tag' => ['en' => 'sky']], - // ['confidence' => 41.704250335693, 'tag' => ['en' => 'landscape']], - // ] - // ], - // 'status' => ['text' => 'success'] - // ]; - - // $response = json_encode($mock_api_response); - // $debug[] = "Mock API response used for file: $file_url"; - - // if ($response) { - // $debug[] = "API call successful for file: $file_url"; - // $data = json_decode($response, true); - // } else { - // $debug[] = "API call failed"; - // echo json_encode(['message' => 'API call failed', 'debug' => $debug]); - // ftp_close($ftp_conn); - // exit; - // } - - // Step 4: Call API with FTP file URL - $api_key = $config['api_key']; - $api_secret = $config['api_secret']; - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, "https://api.imagga.com/v2/tags?image_url=" . urlencode($file_url)); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_USERPWD, "$api_key:$api_secret"); - - $response = curl_exec($ch); - $curl_error = curl_error($ch); - curl_close($ch); + $mock_api_response = [ + 'result' => [ + 'tags' => [ + ['confidence' => 72.304817199707, 'tag' => ['en' => 'star']], + ['confidence' => 67.556610107422, 'tag' => ['en' => 'sun']], + ['confidence' => 60.43567276001, 'tag' => ['en' => 'celestial body']], + ['confidence' => 43.794635772705, 'tag' => ['en' => 'sky']], + ['confidence' => 41.704250335693, 'tag' => ['en' => 'landscape']], + ] + ], + 'status' => ['text' => 'success'] + ]; + + $response = json_encode($mock_api_response); + $debug[] = "Mock API response used for file: $file_url"; if ($response) { $debug[] = "API call successful for file: $file_url"; $data = json_decode($response, true); } else { - $debug[] = "API call failed: $curl_error"; + $debug[] = "API call failed"; echo json_encode(['message' => 'API call failed', 'debug' => $debug]); ftp_close($ftp_conn); exit; } + // Step 4: Call API with FTP file URL + // $api_key = $config['api_key']; + // $api_secret = $config['api_secret']; + + // $ch = curl_init(); + // curl_setopt($ch, CURLOPT_URL, "https://api.imagga.com/v2/tags?image_url=" . urlencode($file_url)); + // curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + // curl_setopt($ch, CURLOPT_USERPWD, "$api_key:$api_secret"); + + // $response = curl_exec($ch); + // $curl_error = curl_error($ch); + // curl_close($ch); + + // if ($response) { + // $debug[] = "API call successful for file: $file_url"; + // $data = json_decode($response, true); + // } else { + // $debug[] = "API call failed: $curl_error"; + // echo json_encode(['message' => 'API call failed', 'debug' => $debug]); + // ftp_close($ftp_conn); + // exit; + // } + // Step 5: Write metadata based on API response if (isset($data['result']['tags']) && count($data['result']['tags']) > 0) { $tags = []; diff --git a/final/js/app.js b/final/js/app.js index b1f2c7a..e15c5b5 100644 --- a/final/js/app.js +++ b/final/js/app.js @@ -156,8 +156,8 @@ function processImage() { tag.tag } (Confidence: ${tag.confidence.toFixed(2)}%)`; - li.appendChild(checkbox); li.appendChild(label); + li.appendChild(checkbox); ul.appendChild(li); }); } From 5d5f0c59abd271c43f58461ba1b20ec049cae3f8 Mon Sep 17 00:00:00 2001 From: Richard Hong Date: Sat, 7 Dec 2024 11:39:39 -0600 Subject: [PATCH 09/12] cleaning up commented out code, adding new commented code showing limitation of using imagick for writing exif data --- final/embed_metadata.php | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/final/embed_metadata.php b/final/embed_metadata.php index 7ac6fdd..e3fb5ac 100644 --- a/final/embed_metadata.php +++ b/final/embed_metadata.php @@ -10,15 +10,13 @@ $selected_tags = isset($_POST['tags']) ? $_POST['tags'] : []; - // Get the remote file URL from the session - $file_url = $_SESSION['image_path']; // Remote FTP URL + $file_url = $_SESSION['image_path']; try { if (!class_exists('Imagick')) { throw new Exception('Imagick extension is not installed or enabled.'); } - // Download the remote image to a temporary local file $temp_image_path = sys_get_temp_dir() . '/' . basename($file_url); $image_data = file_get_contents($file_url); if ($image_data === false) { @@ -26,13 +24,12 @@ } file_put_contents($temp_image_path, $image_data); - // Load the image using Imagick $imagick = new Imagick($temp_image_path); - // Embed the selected tags into the image metadata $tags_string = implode(', ', $selected_tags); - $imagick->setImageProperty('exif:ImageDescription', $tags_string); - $imagick->setImageProperty('exif:Artist', $_SESSION['username']); + // Imagick only supports writing comments to jpegs, modifying exif data does not persist + // https://github.com/Imagick/imagick/issues/124 + // https://stackoverflow.com/questions/5384962/writing-exif-data-in-php $imagick->setImageProperty('comment', $tags_string); // Debug: Output all properties @@ -40,22 +37,17 @@ error_log("Key: $key, Value: $value"); } - // Set output format $imagick->setImageFormat('jpeg'); - // Save to a temporary output file $temp_output_path = sys_get_temp_dir() . '/output_image.jpg'; $imagick->writeImage($temp_output_path); - // Output the image to the client $image_type = mime_content_type($temp_output_path); header('Content-Type: ' . $image_type); header('Content-Disposition: attachment; filename="modified_image.jpg"'); readfile($temp_output_path); - // Clean up - unlink($temp_output_path); - + unlink($temp_output_path); } catch (Exception $e) { if (isset($imagick)) { $imagick->destroy(); From eeb712d251fd4534865e27f59ef8d009fc572327 Mon Sep 17 00:00:00 2001 From: Richard Hong Date: Sat, 7 Dec 2024 16:47:14 -0600 Subject: [PATCH 10/12] adding styling to affect button layout on login/registration, adding a modal to display metadata for visual confirmation that comments are embedded, adding auto redirect on register to login after 5 seconds, adding functions within app.js to handle modal opening and displaying of metadata, changing when temp_output_path is unlinked to when logging out or when executing php script of display_metadata --- final/css/style.css | 104 ++++++++++++++++++++++- final/display_metadata.php | 169 ++++++++++++++++--------------------- final/embed_metadata.php | 14 ++- final/ftp_upload.php | 1 + final/index.php | 6 +- final/js/app.js | 56 +++++++++++- final/logout.php | 10 ++- final/main.php | 13 +++ final/register.php | 19 ++++- 9 files changed, 284 insertions(+), 108 deletions(-) diff --git a/final/css/style.css b/final/css/style.css index 86e8a23..8629457 100644 --- a/final/css/style.css +++ b/final/css/style.css @@ -15,6 +15,7 @@ body { color: #ffffff; float: right; text-decoration: none; + padding-right: 20px; } .container { margin-top: 70px; @@ -68,13 +69,23 @@ button { transform: translateY(-20px); } } -.debug-window { +.debug-window, +.metadata-review, +#display-metadata-btn-container { background-color: #1f1f1f; padding: 10px; margin-top: 20px; - max-height: 200px; overflow-y: scroll; } + +.debug-window { + display: none; + max-height: 200px; +} + +.metadata-review { + max-height: 1000px; +} #tags-container { margin-top: 20px; } @@ -106,9 +117,98 @@ button { .image-preview { margin-top: 20px; text-align: center; + max-width: 100%; + width: 100%; } .image-preview img { max-width: 100%; height: auto; } + +#auth-actions { + display: flex; +} + +#auth-actions button { + margin: 0 5px; +} + +table { + width: 100%; + border-collapse: collapse; + margin-top: 20px; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +table th, +table td { + padding: 12px; + text-align: left; + border: 1px solid #ddd; + font-size: 1rem; +} + +.category-title { + background-color: #fafafa; + padding: 12px; + border-radius: 6px; + margin-top: 30px; + color: #333; + font-size: 1.3rem; +} + +.category-title::before { + content: "🔍"; + padding-right: 8px; +} + +.modal { + display: none; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0, 0, 0, 0.4); +} + +.modal-content { + background-color: #1f1f1f; + margin: 15% auto; + padding: 20px; + border: 1px solid #888; + width: 80%; + max-width: 900px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + border-radius: 8px; +} + +.close { + color: #aaa; + font-size: 28px; + font-weight: bold; + position: absolute; + top: 100px; + right: 25px; + transition: 0.3s; +} + +.close:hover, +.close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} + +#display-metadata-btn-container { + display: none; +} + +#displayMetadataBtn { + margin-top: 20px; +} diff --git a/final/display_metadata.php b/final/display_metadata.php index 72c4c48..c070dc1 100644 --- a/final/display_metadata.php +++ b/final/display_metadata.php @@ -1,106 +1,87 @@ - - - - - Image Metadata - - - + error_reporting(E_ALL); + ini_set('display_errors', 1); + session_start(); -

Image Metadata

- - -"; + echo "

=== Image Metadata ===

"; + foreach ($categories as $category => $properties) { + if (!empty($properties)) { + echo "
$category Metadata
"; + echo " + + + + + + + "; + + foreach ($properties as $key => $value) { + $formatted_key = ucfirst(str_replace(['exif:', 'jpeg:', 'iptc:', 'xmp:'], '', $key)); + echo ""; + } -} else { - echo "

Imagick is not installed or not enabled.

"; -} + echo " +
PropertyValue
$formatted_key$value
"; + } + } + $imagick->destroy(); + $temp_output_path = sys_get_temp_dir() . '/output_image.jpg'; + unlink($temp_output_path); + } catch (Exception $e) { + echo "

Error using Imagick: " . $e->getMessage() . "

"; + } ?> diff --git a/final/embed_metadata.php b/final/embed_metadata.php index e3fb5ac..a173cd1 100644 --- a/final/embed_metadata.php +++ b/final/embed_metadata.php @@ -11,6 +11,7 @@ $selected_tags = isset($_POST['tags']) ? $_POST['tags'] : []; $file_url = $_SESSION['image_path']; + $file_name = $_SESSION['file_name']; try { if (!class_exists('Imagick')) { @@ -44,10 +45,19 @@ $image_type = mime_content_type($temp_output_path); header('Content-Type: ' . $image_type); - header('Content-Disposition: attachment; filename="modified_image.jpg"'); + header('Content-Disposition: attachment; filename="' . $file_name . '_modified_image.jpg"'); readfile($temp_output_path); - unlink($temp_output_path); + $temp_output_path = sys_get_temp_dir() . '/output_image.jpg'; + $imagick->writeImage($temp_output_path); + + // Ensure file still exists for reference within display_metadata.php + if (!file_exists($temp_output_path)) { + echo "

Error: Image file does not exist at $temp_output_path

"; + exit; + } + + $_SESSION['temp_output_path'] = $temp_output_path; } catch (Exception $e) { if (isset($imagick)) { $imagick->destroy(); diff --git a/final/ftp_upload.php b/final/ftp_upload.php index e2e1ded..feeeda8 100644 --- a/final/ftp_upload.php +++ b/final/ftp_upload.php @@ -19,6 +19,7 @@ if (isset($_FILES['file'])) { $file = $_FILES['file']['tmp_name']; $file_name = basename($_FILES['file']['name']); + $_SESSION['file_name'] = $file_name; $remote_file = "uploads/" . $file_name; // Step 1: Connect to FTP server diff --git a/final/index.php b/final/index.php index 986e00d..d455971 100644 --- a/final/index.php +++ b/final/index.php @@ -52,8 +52,10 @@ - - +
+ + +
diff --git a/final/js/app.js b/final/js/app.js index e15c5b5..d9a63e0 100644 --- a/final/js/app.js +++ b/final/js/app.js @@ -85,6 +85,9 @@ function processImage() { // Show progress indicator progress.style.display = "block"; + // Make debug window visible + debugWindow.style.display = "block"; + // Clear previous debug messages and tags debugWindow.innerHTML = ""; tagsContainer.innerHTML = ""; @@ -206,14 +209,24 @@ function downloadImage() { return response.blob(); }) .then((blob) => { + const dropArea = document.getElementById("drop-area"); + const fullFileName = dropArea + .querySelector("p") + .textContent.trim() + .split(":"); + const fileName = fullFileName[1]?.trim().split(".")[0]; + const fileExtension = fullFileName[1]?.trim().split(".")[1]; + // Create a link to download the file const url = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; - a.download = "modified_image.jpg"; + a.download = `${fileName}_modified_image.jpg`; document.body.appendChild(a); a.click(); a.remove(); + document.getElementById("display-metadata-btn-container").style.display = + "block"; }) .catch((error) => { console.error("Error:", error); @@ -223,3 +236,44 @@ function downloadImage() { debugWindow.appendChild(p); }); } + +const modal = document.getElementById("metadataModal"); +const btn = document.getElementById("displayMetadataBtn"); +const closeModalBtn = document.getElementById("closeModal"); + +function displayMetadata() { + const metadataReview = document.getElementById("metadataReview"); + metadataReview.innerHTML = "

Loading metadata...

"; + + fetch("display_metadata.php") + .then((response) => { + if (!response.ok) { + return response.text().then((text) => { + throw new Error(text); + }); + } + return response.text(); + }) + .then((data) => { + metadataReview.innerHTML = data; + modal.style.display = "block"; + }) + .catch((error) => { + console.error("Error:", error); + metadataReview.innerHTML = `

Error: ${error.message}

`; + }); +} + +btn.onclick = function () { + displayMetadata(); +}; + +closeModalBtn.onclick = function () { + modal.style.display = "none"; +}; + +window.onclick = function (event) { + if (event.target === modal) { + modal.style.display = "none"; + } +}; diff --git a/final/logout.php b/final/logout.php index e5ab4b6..3425691 100644 --- a/final/logout.php +++ b/final/logout.php @@ -1,6 +1,8 @@ diff --git a/final/main.php b/final/main.php index 4876fab..ca70267 100644 --- a/final/main.php +++ b/final/main.php @@ -58,6 +58,19 @@
+ +
+ +
+ + + diff --git a/final/register.php b/final/register.php index 4bcc1e1..fd8320c 100644 --- a/final/register.php +++ b/final/register.php @@ -25,7 +25,18 @@ $stmt->bindParam(':password', $password); $stmt->execute(); - echo "Registration successful!"; + echo "Registration successful! Redirecting to login in 5 second(s).

"; + echo ""; } catch (PDOException $e) { if ($e->getCode() == 23000) { echo "Username or email already exists."; @@ -44,8 +55,10 @@ - - +

+ + +
From 9e1c39765b258c8d74a63f4a3a0439f699b562c8 Mon Sep 17 00:00:00 2001 From: Richard Hong Date: Sat, 7 Dec 2024 19:13:45 -0600 Subject: [PATCH 11/12] changing sitegroun ftp account home path and adding ftp_path variable accordingly to config.php, referencing ftp_path where needed in php files --- final/config.php.example | 1 + final/display_metadata.php | 38 +++++++++++++++++++++----------- final/embed_metadata.php | 45 ++++++++++++++++++++++++++++++++++++-- final/ftp_upload.php | 5 +++-- 4 files changed, 72 insertions(+), 17 deletions(-) diff --git a/final/config.php.example b/final/config.php.example index 720388b..bc4afbb 100644 --- a/final/config.php.example +++ b/final/config.php.example @@ -5,6 +5,7 @@ return [ 'ftp_pass' => "FTP_PASS", 'ftp_port' => "21", 'ftp_domain' => 'FTP_DOMAIN', + 'ftp_path' => 'FTP_PATH, 'db_host' => 'DB_HOST', 'db_user' => 'DB_USER', 'db_pwd' => 'DB_PWD', diff --git a/final/display_metadata.php b/final/display_metadata.php index c070dc1..2c2e701 100644 --- a/final/display_metadata.php +++ b/final/display_metadata.php @@ -3,29 +3,37 @@ ini_set('display_errors', 1); session_start(); + $config = include 'config.php'; + $ftp_domain = $config['ftp_domain']; + if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) { header('HTTP/1.1 401 Unauthorized'); exit; } - $file_url = isset($_SESSION['temp_output_path']) ? $_SESSION['temp_output_path'] : ''; + $file_name = $_SESSION['file_name']; + $base_name = pathinfo($file_name, PATHINFO_FILENAME); - if (empty($file_url)) { - echo "

Error: Image path is not set in the session.

"; - exit; - } + $image_url = $ftp_domain . "/uploads/". $base_name . '_modified_image.jpg'; + $temp_image_path = sys_get_temp_dir() . '/' . basename($image_url); - if (!file_exists($file_url)) { - echo "

Error: Image file does not exist at $file_url

"; + if (empty($image_url)) { + echo "

Error: Image path is not set in the session.

"; exit; } try { - if (!class_exists('Imagick')) { - throw new Exception('Imagick extension is not installed or not enabled.'); - } + $image_data = file_get_contents($image_url); + if ($image_data === false) { + throw new Exception('Failed to download the image file.'); + } + file_put_contents($temp_image_path, $image_data); + + if (!class_exists('Imagick')) { + throw new Exception('Imagick extension is not installed or enabled.'); + } - $imagick = new Imagick($file_url); + $imagick = new Imagick($temp_image_path); if (!$imagick) { echo "

Error: Imagick failed to load the image.

"; @@ -79,9 +87,13 @@ } } $imagick->destroy(); - $temp_output_path = sys_get_temp_dir() . '/output_image.jpg'; - unlink($temp_output_path); + if (file_exists($temp_image_path)) { + unlink($temp_image_path); + } } catch (Exception $e) { echo "

Error using Imagick: " . $e->getMessage() . "

"; + if (file_exists($temp_image_path)) { + unlink($temp_image_path); + } } ?> diff --git a/final/embed_metadata.php b/final/embed_metadata.php index a173cd1..c270ae1 100644 --- a/final/embed_metadata.php +++ b/final/embed_metadata.php @@ -3,6 +3,13 @@ ini_set('display_errors', 1); session_start(); + $config = include 'config.php'; + $ftp_server = $config['ftp_server']; + $ftp_port = $config['ftp_port']; + $ftp_user = $config['ftp_user']; + $ftp_pass = $config['ftp_pass']; + $ftp_path = $config['ftp_path']; + if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) { header('HTTP/1.1 401 Unauthorized'); exit; @@ -12,6 +19,9 @@ $file_url = $_SESSION['image_path']; $file_name = $_SESSION['file_name']; + $base_name = pathinfo($file_name, PATHINFO_FILENAME); + + $remote_file = $ftp_path . $base_name . '_modified_image.jpg'; try { if (!class_exists('Imagick')) { @@ -51,13 +61,44 @@ $temp_output_path = sys_get_temp_dir() . '/output_image.jpg'; $imagick->writeImage($temp_output_path); - // Ensure file still exists for reference within display_metadata.php + $ftp_conn = ftp_connect($ftp_server, $ftp_port); + if ($ftp_conn) { + $debug[] = "Connected to FTP server: $ftp_server:$ftp_port"; + } else { + echo json_encode(['message' => 'Could not connect to FTP server', 'debug' => $debug]); + exit; + } + + $login = ftp_login($ftp_conn, $ftp_user, $ftp_pass); + if ($login) { + $debug[] = "FTP login successful for user: $ftp_user"; + ftp_pasv($ftp_conn, true); // Enable passive mode + } else { + $ftp_response = ftp_raw($ftp_conn, 'NOOP'); + $debug[] = "FTP login failed for user: $ftp_user"; + $debug[] = "FTP Server Response: " . implode(" | ", $ftp_response); + ftp_close($ftp_conn); + echo json_encode(['message' => 'FTP login failed', 'debug' => $debug]); + exit; + } + + if (ftp_put($ftp_conn, $remote_file, $temp_output_path, FTP_BINARY)) { + $debug[] = "File uploaded successfully to: $remote_file"; + } + + if (file_exists($temp_image_path)) { + unlink($temp_image_path); + } + + if (file_exists($temp_output_path)) { + unlink($temp_output_path); + } + if (!file_exists($temp_output_path)) { echo "

Error: Image file does not exist at $temp_output_path

"; exit; } - $_SESSION['temp_output_path'] = $temp_output_path; } catch (Exception $e) { if (isset($imagick)) { $imagick->destroy(); diff --git a/final/ftp_upload.php b/final/ftp_upload.php index feeeda8..186b552 100644 --- a/final/ftp_upload.php +++ b/final/ftp_upload.php @@ -15,12 +15,13 @@ $ftp_port = $config['ftp_port']; $ftp_user = $config['ftp_user']; $ftp_pass = $config['ftp_pass']; +$ftp_path = $config['ftp_path']; if (isset($_FILES['file'])) { $file = $_FILES['file']['tmp_name']; $file_name = basename($_FILES['file']['name']); $_SESSION['file_name'] = $file_name; - $remote_file = "uploads/" . $file_name; + $remote_file = $ftp_path . $file_name; // Step 1: Connect to FTP server $ftp_conn = ftp_connect($ftp_server, $ftp_port); @@ -123,7 +124,7 @@ $metadata_content = "Image Description: " . $description . "\nUploaded File Name: " . $file_name; // Prepare metadata file paths - $remote_file = "uploads/" . pathinfo($file_name, PATHINFO_FILENAME) . "_metadata.txt"; + $remote_file = $ftp_path . pathinfo($file_name, PATHINFO_FILENAME) . "_metadata.txt"; $local_upload = './uploads/'; $metadata_file = $local_upload . pathinfo($file_name, PATHINFO_FILENAME) . "_metadata.txt"; From 4276c5a6d36f8becf2ca34aa1fdf16bdfb036a3c Mon Sep 17 00:00:00 2001 From: Richard Hong Date: Sun, 8 Dec 2024 16:57:13 -0600 Subject: [PATCH 12/12] copying styling from index.php into register.php --- final/register.php | 93 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/final/register.php b/final/register.php index fd8320c..609c416 100644 --- a/final/register.php +++ b/final/register.php @@ -4,6 +4,99 @@ Register +
Image Tagging App