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 #= $data['code']; ?>
+
+
No Logs found
+
+
+
+
+
+