diff --git a/404.php b/404.php new file mode 100644 index 0000000..02bfa53 --- /dev/null +++ b/404.php @@ -0,0 +1,17 @@ + + + + + + 404 Error | Armox IP Logger + + + +
+
+

404 Error

+

Page not found

+
+
+ + \ No newline at end of file diff --git a/api/iplogger.php b/api/iplogger.php new file mode 100644 index 0000000..c675ac1 --- /dev/null +++ b/api/iplogger.php @@ -0,0 +1,117 @@ +fetch(); + $request->closeCursor(); + + if(createShortUrl($db, $url, $shortUrlCode, $data['id'])) { + $response = array( + "shortUrlCode" => $shortUrlCode, + "trackerCode" => $trackerCode + ); + + http_response_code(200); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Success", + "response" => $response + ) + ); + } else { + http_response_code(200); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Unable to create short url" + ) + ); + } + } else { + http_response_code(200); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Unable to create short url" + ) + ); + } + } else { + http_response_code(200); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Unable to create tracker" + ) + ); + } + } else { + http_response_code(200); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Invalid URL" + ) + ); + } + } else { + http_response_code(200); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Please complete all fields" + ) + ); + } + } else { + http_response_code(200); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Please complete all fields" + ) + ); + } + + break; + default: + http_response_code(405); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Method Not Allowed" + ) + ); + + break; + } diff --git a/api/track.php b/api/track.php new file mode 100644 index 0000000..c597c60 --- /dev/null +++ b/api/track.php @@ -0,0 +1,76 @@ +fetch()) { + $log['id'] = $data['id']; + $log['ip'] = htmlspecialchars($data['ip']); + $log['userAgent'] = htmlspecialchars($data['user_agent']); + $log['clickedAt'] = htmlspecialchars($data['clicked_at']); + $response[] = $log; + } + + $request->closeCursor(); + + http_response_code(200); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Success", + "response" => $response + ) + ); + } else { + http_response_code(200); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "No logs found" + ) + ); + } + } else { + http_response_code(404); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Invalid tracker" + ) + ); + } + } else { + http_response_code(404); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Invalid tracker" + ) + ); + } + + break; + default: + http_response_code(405); + + header('content-type:application/json'); + echo json_encode( + array( + "message" => "Method Not Allowed" + ) + ); + + break; + } + \ No newline at end of file diff --git a/includes/css/style.css b/includes/css/style.css new file mode 100644 index 0000000..8e70e72 --- /dev/null +++ b/includes/css/style.css @@ -0,0 +1,148 @@ +@import url('https://fonts.googleapis.com/css?family=Poppins:400,600'); + +body { + margin: 0; + background-color: #2C2C2C; + font-family: 'Poppins', sans-serif; + color: #ffffff; + font-size: 16px; + font-weight: 400; + line-height: 1.75; +} + +h1, +h2, +h3 { + font-weight: 600; + line-height: 1.3; + margin-bottom: 20px; + font-family: 'Poppins', sans-serif; +} + +h1 { + text-align: center; + margin-top: 0px; + font-size: 40px; +} + +h2 { + text-align: center; + font-size: 32px; + color: #596167; +} + +h3 { + text-align: center; + font-size: 26px; + color: #596167; +} + +a { + color: #309ADD; +} + +.website-container { + max-width: 800px; + width: 100%; + margin: auto; +} + +.app, +.result, +.content { + margin: 20px; +} + +.app { + background-color: #373737; + border-radius: 15px; + padding: 40px; +} + +.app-result { + text-align: center; + padding: 20px 40px; +} + +.form-create-url { + width: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; +} + +.url-field { + background-color: black; + color: white; + border: none; + margin-right: 10px; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + padding: 10px; + font-size: 16px; +} + +.btn-create { + background-color: black; + color: white; + border: none; + padding: 5px; + -ms-flex-preferred-size: 100px; + flex-basis: 100px; + font-size: 16px; + border-radius: 5px; + cursor: pointer; +} + +.content { + margin-top: 40px; +} + +.table-responsive { + overflow-x: auto; +} + +.logs { + background-color: #373737; + color: white; + margin-top: 20px; + border-collapse: collapse; +} + +td, +th { + border: 1px solid white; + padding: 10px; +} + +@media only screen and (max-width: 500px) { + .app { + padding: 20px; + } +} + +@media only screen and (max-width: 400px) { + .form-create-url { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + } + .url-field { + -webkit-box-flex: 0; + -ms-flex-positive: 0; + flex-grow: 0; + margin-right: 0px; + margin-bottom: 10px; + } + .btn-create { + padding: 15px 10px; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } +} diff --git a/includes/js/app.js b/includes/js/app.js new file mode 100644 index 0000000..ee3cc74 --- /dev/null +++ b/includes/js/app.js @@ -0,0 +1,52 @@ +/* Return a boolean depending on if it's json */ +function isJson(response) { + try { + JSON.parse(response); + return true; + } catch (e) { + return false; + } +} + +/* Request to create iplogger */ +function createIpLogger(e) { + e.preventDefault() + let url = document.getElementById("url").value + + let xhr = new XMLHttpRequest() + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + formElt.reset() + + if(isJson(xhr.responseText)) { + let response = JSON.parse(xhr.responseText) + + if(response.message === "Success") { + document.getElementById("result").innerHTML = "Your Link Logger is : " + document.URL.substr(0, document.URL.lastIndexOf('/')) + "/link.php?id=" + response.response.shortUrlCode + "
Your Tracker Link is : " + document.URL.substr(0, document.URL.lastIndexOf('/')) + "/tracker.php?id=" + response.response.trackerCode + "

Please take note because you won't be able to do it after" + } else if(response.message === "Please complete all fields") { + alert(response.message) + } else if(response.message === "Invalid URL") { + alert(response.message) + } else if(response.message === "Unable to create tracker") { + alert(response.message) + } else if(response.message === "Unable to create short url") { + alert(response.message) + } else { + alert("Server Error") + } + } else { + alert("Server Error") + } + } + } + xhr.open("POST", "api/iplogger.php") + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest") + xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") + xhr.send("url="+url) +} + +let formElt = document.getElementById("form") + +formElt.addEventListener("submit", function(e) { + createIpLogger(e) +}) diff --git a/includes/js/track.js b/includes/js/track.js new file mode 100644 index 0000000..b0e2930 --- /dev/null +++ b/includes/js/track.js @@ -0,0 +1,99 @@ +/* Retrieve tracker code from URL */ +function getTrackerCode() { + let code = new URL(window.location).searchParams.get("id") + return code +} + +/* Return a boolean depending on if it's json */ +function isJson(response) { + try { + JSON.parse(response); + return true; + } catch (e) { + return false; + } +} + +/* Load logs in DOM */ +function loadLogs(logs) { + let resultElt = document.getElementById("result") + resultElt.innerHTML = "" + + let tableResponsiveElt = document.createElement("div") + tableResponsiveElt.className = "table-responsive" + + let tableElt = document.createElement("table") + tableElt.className = "logs" + + let trElt = document.createElement("tr") + + let thDateElt = document.createElement("th") + thDateElt.textContent = "Date" + + let thIpElt = document.createElement("th") + thIpElt.textContent = "IP" + + let thUserAgentElt = document.createElement("th") + thUserAgentElt.textContent = "User Agent" + + trElt.appendChild(thDateElt) + trElt.appendChild(thIpElt) + trElt.appendChild(thUserAgentElt) + tableElt.appendChild(trElt) + + logs.forEach(log => { + trElt = document.createElement("tr") + + tdDateElt = document.createElement("td") + tdDateElt.textContent = log.clickedAt + + tdIpElt = document.createElement("td") + tdIpElt.textContent = log.ip + + tdUserAgentElt = document.createElement("td") + tdUserAgentElt.textContent = log.userAgent + + trElt.appendChild(tdDateElt) + trElt.appendChild(tdIpElt) + trElt.appendChild(tdUserAgentElt) + + tableElt.appendChild(trElt) + tableResponsiveElt.appendChild(tableElt) + + resultElt.appendChild(tableResponsiveElt) + }) +} + + +/* Request to GET log of a tracker */ +function getLogs() { + let xhr = new XMLHttpRequest() + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + if(isJson(xhr.responseText)) { + let response = JSON.parse(xhr.responseText) + + if(response.message === "Success") { + loadLogs(response.response); + } else if(response.message === "Invalid tracker") { + window.location.href = "404.php"; + } else if(response.message === "No logs found") { + // Nothing + } else { + alert("Server Error"); + } + } else { + alert("Server Error"); + } + + setTimeout(() => { + getLogs() + }, 5000); + } + } + xhr.open('GET', 'api/track.php?id=' + getTrackerCode() + '&_=' + new Date().getTime(), true) // Removing cache with Date().getTime() + xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest') + xhr.send() +} + +getLogs() diff --git a/includes/php/connect-db.php b/includes/php/connect-db.php new file mode 100644 index 0000000..f4d5f22 --- /dev/null +++ b/includes/php/connect-db.php @@ -0,0 +1,9 @@ +getMessage()); + } diff --git a/includes/php/tracker.php b/includes/php/tracker.php new file mode 100644 index 0000000..f5f20e8 --- /dev/null +++ b/includes/php/tracker.php @@ -0,0 +1,141 @@ +prepare( + 'SELECT * + FROM tracker' + ); + $request->execute(); + + return $request; + } + + /* Retrieve a Tracker by tracker code */ + function getTracker($db, $code) { + $request = $db->prepare( + 'SELECT * + FROM tracker + WHERE code = :code' + ); + $request->bindParam(":code", $code); + $request->execute(); + + return $request; + } + + /* Return boolean if tracker exist or not */ + function trackerExist($db, $code) { + $request = $db->prepare( + 'SELECT count(*) AS result + FROM tracker + WHERE code = :code' + ); + $request->bindParam(":code", $code); + $request->execute(); + + $response = $request->fetch(); + $request->closeCursor(); + + $result = (int)$response['result']; + if($result === 1) { + $result = true; + } else { + $result = false; + } + + return $result; + } + + /* Return boolean if tracker exist or not */ + function trackerExistById($db, $id) { + $request = $db->prepare( + 'SELECT count(*) AS result + FROM tracker + WHERE id = :id' + ); + $request->bindParam(":id", $id); + $request->execute(); + + $response = $request->fetch(); + $request->closeCursor(); + + $result = (int)$response['result']; + if($result === 1) { + $result = true; + } else { + $result = false; + } + + return $result; + } + + /* Insert tracker in DB and return boolean if is successfull or not */ + function createTracker($db, $code) { + $request = $db->prepare( + 'INSERT INTO tracker(code) + VALUES(:code)' + ); + $request->bindParam(":code", $code); + $request->execute(); + $request->closeCursor(); + + return $request->rowCount(); + } + + /* Retrieve all logs of a tracker */ + function getTrackerLogs($db, $code) { + $request = $db->prepare( + 'SELECT tracker.code, log.id, log.clicked_at, log.ip, log.user_agent + FROM log + INNER JOIN tracker + ON log.tracker_id = tracker.id + WHERE tracker.code = :code + ORDER BY clicked_at DESC' + ); + $request->bindParam(":code", $code); + $request->execute(); + + return $request; + } + + /* Return boolean if tracker logs exist or not */ + function trackerLogsExist($db, $code) { + $request = $db->prepare( + 'SELECT count(*) AS result + FROM log + INNER JOIN tracker + ON log.tracker_id = tracker.id + WHERE tracker.code = :code' + ); + $request->bindParam(":code", $code); + $request->execute(); + + $response = $request->fetch(); + $request->closeCursor(); + + $result = (int)$response['result']; + if($result > 0) { + $result = true; + } else { + $result = false; + } + + return $result; + } + + /* Insert tracker log in DB and return boolean if is successfull or not */ + function addTrackerLog($db, $ip, $userAgent, $code) { + $request = $db->prepare( + 'INSERT INTO log(ip, user_agent, clicked_at, tracker_id) + VALUES(:ip, :userAgent, NOW(), :trackerId)' + ); + $request->bindParam(":ip", $ip); + $request->bindParam(":userAgent", $userAgent); + $request->bindParam(":trackerId", $code); + $request->execute(); + $request->closeCursor(); + + return $request->rowCount(); + } diff --git a/includes/php/url-shortener.php b/includes/php/url-shortener.php new file mode 100644 index 0000000..578eca1 --- /dev/null +++ b/includes/php/url-shortener.php @@ -0,0 +1,64 @@ +prepare( + 'SELECT * + FROM short_url' + ); + $request->execute(); + + return $request; + } + + /* Retrieve a short url by short url code */ + function getShortUrl($db, $code) { + $request = $db->prepare( + 'SELECT * + FROM short_url + WHERE code = :code' + ); + $request->bindParam(":code", $code); + $request->execute(); + + return $request; + } + + /* Return boolean if short url exist or not exist */ + function shortUrlExist($db, $code) { + $request = $db->prepare( + 'SELECT count(*) AS result + FROM short_url + WHERE code = :code' + ); + $request->bindParam(":code", $code); + $request->execute(); + + $response = $request->fetch(); + $request->closeCursor(); + + $result = (int)$response['result']; + if($result === 1) { + $result = true; + } else { + $result = false; + } + + return $result; + } + + /* Insert short URL in DB and return boolean if is successfull or not */ + function createShortUrl($db, $url, $code, $trackerId) { + $request = $db->prepare( + 'INSERT INTO short_url(url, code, tracker_id) + VALUES(:url, :code, :trackerId)' + ); + $request->bindParam(":url", $url); + $request->bindParam(":code", $code); + $request->bindParam(":trackerId", $trackerId); + $request->execute(); + $request->closeCursor(); + + return $request->rowCount(); + } diff --git a/index.php b/index.php new file mode 100644 index 0000000..59c5cd0 --- /dev/null +++ b/index.php @@ -0,0 +1,24 @@ + + + + + + Armox IP Logger + + + +
+
+

Armox IP Logger

+

Create URL

+
+ + +
+
+
+
+ + + + \ No newline at end of file diff --git a/link.php b/link.php new file mode 100644 index 0000000..e218881 --- /dev/null +++ b/link.php @@ -0,0 +1,34 @@ +fetch(); + $request->closeCursor(); + + if(trackerExistById($db, $data['tracker_id'])) { + $ip = $_SERVER['REMOTE_ADDR']; + $userAgent = $_SERVER['HTTP_USER_AGENT']; + + if(addTrackerLog($db, $ip, $userAgent, $data['tracker_id'])) { + header('Location: ' . htmlspecialchars($data['url'])); + exit(); + } else { + header('Location: 404.php'); + } + } else { + header('Location: 404.php'); + exit(); + } + } else { + header('Location: 404.php'); + exit(); + } + } else { + header('Location: 404.php'); + exit(); + } diff --git a/preview.gif b/preview.gif new file mode 100644 index 0000000..1e5ee82 Binary files /dev/null and b/preview.gif differ diff --git a/tracker.php b/tracker.php new file mode 100644 index 0000000..8a111d1 --- /dev/null +++ b/tracker.php @@ -0,0 +1,40 @@ +fetch(); + $request->closeCursor(); + } else { + header('Location: 404.php'); + exit(); + } + } +?> + + + + + + + Tracking #<?= $data['code']; ?> | Armox IP Logger + + + +
+
+

Tracking #

+
+

No Logs found

+
+
+
+ + +