commit 6073a08a6dc398b04174fae198d6101f0106fef4 Author: xodivorce Date: Thu Aug 29 19:05:53 2024 +0530 v1.0.1 diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..ce63371e Binary files /dev/null and b/.DS_Store differ diff --git a/.htaccess b/.htaccess new file mode 100644 index 00000000..bb6c821a --- /dev/null +++ b/.htaccess @@ -0,0 +1,6 @@ +RewriteEngine On + +RewriteCond $1 !^(index\.php) +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule ^(.*)$ index.php?/$1 [L] \ No newline at end of file diff --git a/assets/.DS_Store b/assets/.DS_Store new file mode 100644 index 00000000..2a87f346 Binary files /dev/null and b/assets/.DS_Store differ diff --git a/assets/css/footer.css b/assets/css/footer.css new file mode 100644 index 00000000..89dc0bea --- /dev/null +++ b/assets/css/footer.css @@ -0,0 +1,48 @@ +footer { + background-color: #F8F8FD; + padding: 33px 20px; /* Increased padding for a larger footer */ + border: none; + width: 100%; + box-sizing: border-box; +} + +.footer-container { + display: flex; + justify-content: space-between; + align-items: center; + max-width: 1120px; + font-size: 12px; /* Slightly increased font size */ + margin: 0 auto; + width: 100%; + box-sizing: border-box; + flex-wrap: wrap; +} + +.footer-container p { + margin: 0; + padding-bottom: 20px; /* Increased padding for spacing */ +} + +.footer-links { + margin-top: 15px; /* Increased margin for better spacing */ +} + +.footer-links a { + margin: 0 12px; /* Slightly increased margin between links */ + text-decoration: none; + color: #A2ABB8; + font-weight: 550; + font-size: 10px; +} + +.footer-links a:hover { + text-decoration: underline; +} + +.footer-img { + width: 20px; + margin: 0; + position: relative; + top: 2px; + left: -5px; +} diff --git a/assets/css/header.css b/assets/css/header.css new file mode 100644 index 00000000..6bed6c70 --- /dev/null +++ b/assets/css/header.css @@ -0,0 +1,55 @@ +/* header.css */ + +header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20px; + background-color: #ffffff; + border-bottom: 1px solid #F2F2F2; + position: fixed; + top: 0; + width: 97%; + z-index: 1000; +} + +.logo { + display: flex; + align-items: center; + font-weight: 500; + font-size: 18px; +} + +.logo-img { + width: 35px; + margin-right: 10px; /* Spacing between logo and text */ +} + +nav ul { + list-style: none; + display: flex; + gap: 40px; + margin: 0; +} + +nav ul li a { + text-decoration: none; + color: #697483; /* Default color for inactive links */ + font-size: 14px; + font-weight: 500; + transition: color 0.3s; /* Smooth color transition */ +} + +nav ul li a.active { + color: #BEC7D5; /* Color for active link */ +} + +nav ul li a:not(.disabled):hover { + color: #272B2F; /* Color on hover for non-disabled links */ +} + +nav ul li a.disabled { + color: #BEC7D5; /* Color for disabled link */ + pointer-events: none; /* Disable click events */ + cursor: default; /* Change cursor to default */ +} diff --git a/assets/css/home.css b/assets/css/home.css new file mode 100644 index 00000000..ed845c1f --- /dev/null +++ b/assets/css/home.css @@ -0,0 +1,203 @@ +body { + font-family: "Montserrat", sans-serif; + margin: 0; + padding: 0; + background-color: #ffffff; + color: #333333; +} + +main { + padding: 60px 20px; + text-align: center; +} + +.shorten-section h1 { + color: #171C24; + margin-top: 65px; + font-size: 45px; + font-weight: 700; + margin-bottom: 0px; +} + +.shorten-section h2 { + color: #677583; + margin-top: 0px; + font-size: 45px; + font-weight: 700; + margin-bottom: 45px; +} + + +.shorten-section p { + color:#3C4B62; + margin-top: -15px; + margin-bottom: 45px; + font-size: 18px; + line-height: 35px; +} +.shorten-form { + display: flex; + justify-content: center; + align-items: center; + gap: 10px; + margin-bottom: 80px; + position: relative; +} + +.shorten-form input { + font-family: "Montserrat", sans-serif; + padding: 18px 45px; /* Adjust padding to make space for the icon */ + width: 450px; + border: none; /* Remove border */ + border-radius: 5px; /* Rounded corners */ + font-size: 16px; + background-color: #ffffff; + color: #333333; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.082); /* Soft shadow */ + outline: none; + box-sizing: border-box; + transition: box-shadow 0.3s ease; +} + +.shorten-form input::placeholder { + color: #BEC7D5; /* Light gray placeholder text */ + font-weight: 500; +} + +.shorten-form input:focus { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.150); /* Slightly stronger shadow on focus */ +} + +.shorten-form input:hover { + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.150); /* Slight shadow change on hover */ +} + +.shorten-form .search-icon { + position: absolute; + left: 16px; /* Position the icon inside the input */ + font-size: 20px; + color: #BEC7D5; +} + +.shorten-form button { + font-family: "Montserrat", sans-serif; + padding: 18px 45px; + background-color: #4d555cec; + color: #ffffff; + border: none; + border-radius: 5px; /* Same rounded corners as the input */ + cursor: pointer; + font-weight: 600; + font-size: 16px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.082); /* Same shadow as the input */ + outline: none; + box-sizing: border-box; + transition: box-shadow 0.3s ease, background-color 0.3s ease; +} + +.shorten-form button:hover, +.shorten-form button.typing-active { + background-color: #171C24; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.250); /* Slight shadow change on hover */ +} + +.shorten-form button:focus { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.250); /* Slightly stronger shadow on focus */ +} + +.shortened-links h2 { + font-size: 18px; + margin-right: 500px; + margin-bottom: 25px; + font-weight: 550; + color: #A2ABB8; +} +.custom-link { + color: #387FFF; + text-decoration: none; + position: relative; +} +.custom-link::after { + content: ""; + display: block; + height: 1px; + background-color: #387FFF; + position: absolute; + bottom: -2px; /* Adjust this value to position the underline */ + left: 0; + right: 0; + transform: scaleX(0); + transition: transform 0.3s; +} +.custom-link:hover::after { + transform: scaleX(1); +} + + +#links-list { + list-style: none; + padding: 0; + max-width: 700px; + margin: 0 auto; + font-size: 16px; +} + +#links-list li { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20px; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 8px; + margin-bottom: 15px; +} + +.link-icon { + margin-right: -20px; + +} + +.link-info { + display: flex; + flex-direction: column; + flex-grow: 1; + max-width: 500px; +} + +.short-link { + font-weight: 550; + margin-bottom: 3px; + color:#171C24 ; + white-space: nowrap; + text-overflow: ellipsis; + margin-right: 380px; + font-size: 16px; +} + +.long-link { + color: #677583; + overflow: hidden; + margin-bottom: 0px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + text-align: left; +} + +.copy-btn, +.delete-btn { + background: none; + border: none; + cursor: pointer; + width: 24px; + height: 24px; + padding: 0; +} + +.copy-btn img, +.delete-btn img { + width: 100%; + height: 100%; +} + diff --git a/assets/images/.DS_Store b/assets/images/.DS_Store new file mode 100644 index 00000000..51d73eb5 Binary files /dev/null and b/assets/images/.DS_Store differ diff --git a/assets/images/copy.png b/assets/images/copy.png new file mode 100644 index 00000000..f577f789 Binary files /dev/null and b/assets/images/copy.png differ diff --git a/assets/images/delete.png b/assets/images/delete.png new file mode 100644 index 00000000..4568bd32 Binary files /dev/null and b/assets/images/delete.png differ diff --git a/assets/images/url.png b/assets/images/url.png new file mode 100644 index 00000000..a5f94ded Binary files /dev/null and b/assets/images/url.png differ diff --git a/assets/images/url.svg b/assets/images/url.svg new file mode 100644 index 00000000..8140f6d8 --- /dev/null +++ b/assets/images/url.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/js/header.js b/assets/js/header.js new file mode 100644 index 00000000..e69de29b diff --git a/assets/js/home.js b/assets/js/home.js new file mode 100644 index 00000000..41977676 --- /dev/null +++ b/assets/js/home.js @@ -0,0 +1,69 @@ +const form = document.querySelector(".shorten-form"), + urlInput = document.querySelector("#url-input"), + shortenBtn = document.querySelector("#shorten-btn"), + linksList = document.querySelector("#links-list"); + +shortenBtn.onclick = () => { + let xhr = new XMLHttpRequest(); + xhr.open("POST", "php/url-controll.php", true); + xhr.onload = () => { + if (xhr.readyState == 4 && xhr.status == 200) { + let data = xhr.response; + if (data.length <= 5) { + let domain = "localhost/url/"; + let shortenURL = domain + data; + + let newRow = ` +
  • + + + + +
  • + `; + linksList.insertAdjacentHTML('afterbegin', newRow); + urlInput.value = ""; // Clear the input field + location.reload(); // Reload the page after shortening + } else { + alert(data); + } + } + }; + let formData = new FormData(); + formData.append("full_url", urlInput.value); + xhr.send(formData); +}; + +// Handle copy button clicks +document.addEventListener('click', function(e) { + if (e.target.closest('.copy-btn')) { + const linkInfo = e.target.closest('li').querySelector('.short-link').textContent; + navigator.clipboard.writeText(linkInfo).catch(err => { + console.error('Failed to copy text: ', err); + }); + } + + // Handle delete button clicks + document.querySelectorAll(".delete-btn").forEach((deleteBtn) => { + deleteBtn.addEventListener("click", function () { + const linkItem = this.closest("li"); + const shortenURL = linkItem.querySelector(".short-link").textContent; + + let xhr = new XMLHttpRequest(); + xhr.open("GET", `php/delete.php?id=${shortenURL.split('/').pop()}`, true); + xhr.onload = () => { + if (xhr.readyState == 4 && xhr.status == 200) { + if (xhr.responseText === "success") { + linkItem.remove(); + } else { + alert("Failed to delete the URL."); + } + } + }; + xhr.send(); + }); + }); +}); diff --git a/footer.php b/footer.php new file mode 100644 index 00000000..4e53967a --- /dev/null +++ b/footer.php @@ -0,0 +1,18 @@ + + + + diff --git a/header.php b/header.php new file mode 100644 index 00000000..dad454bf --- /dev/null +++ b/header.php @@ -0,0 +1,16 @@ + +
    + + +
    + diff --git a/home.php b/home.php new file mode 100644 index 00000000..5a0e6793 --- /dev/null +++ b/home.php @@ -0,0 +1,50 @@ + + + + + + + Xeorl - Shorten your links + + + + + + +
    +
    +

    Open source inits.

    +

    Lovingly hand-crafted.

    +

    Premium link shortening for use in web, iOS, Android, and
    + desktop apps. Supported for urls. Completely open source, MIT
    + licensed and built by xodivorce.

    +
    + + +
    + +
    +
    + + + + diff --git a/index.php b/index.php new file mode 100644 index 00000000..c9d21341 --- /dev/null +++ b/index.php @@ -0,0 +1,104 @@ + $val) { + $u = mysqli_real_escape_string($conn, $key); + $new_url = str_replace('/', '', $u); + } + + // Query the database for the full URL associated with the shortened URL + $sql = mysqli_query($conn, "SELECT full_url FROM url WHERE shorten_url = '{$new_url}'"); + if (mysqli_num_rows($sql) > 0) { + // Increment the click count for the shortened URL + $sql2 = mysqli_query($conn, "UPDATE url SET clicks = clicks + 1 WHERE shorten_url = '{$new_url}'"); + if ($sql2) { + // Fetch the full URL and redirect to it + $full_url = mysqli_fetch_assoc($sql); + header("Location:" . $full_url['full_url']); + exit(); // Stop further script execution after redirection + } + } +} +?> + + + + + + + Xeorl - Shorten your links + + + + + + +
    +
    +

    Open source inits.

    +

    Lovingly hand-crafted.

    +

    Premium link shortening for use in web, iOS, Android, and
    desktop apps. Supported for urls. Completely open source, MIT
    licensed and built by xodivorce.

    +
    + + +
    + +
    +
    + + + + diff --git a/php/config.php b/php/config.php new file mode 100644 index 00000000..8261334f --- /dev/null +++ b/php/config.php @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/php/delete.php b/php/delete.php new file mode 100644 index 00000000..bcd64238 --- /dev/null +++ b/php/delete.php @@ -0,0 +1,15 @@ + diff --git a/php/url-controll.php b/php/url-controll.php new file mode 100644 index 00000000..33a31309 --- /dev/null +++ b/php/url-controll.php @@ -0,0 +1,23 @@ + 0){ + echo "Something went wrong. Please generate again!"; + }else{ + $sql2 = mysqli_query($conn, "INSERT INTO url (full_url, shorten_url, clicks) + VALUES ('{$full_url}', '{$ran_url}', '0')"); + if($sql2){ + $sql3 = mysqli_query($conn, "SELECT shorten_url FROM url WHERE shorten_url = '{$ran_url}'"); + if(mysqli_num_rows($sql3) > 0){ + $shorten_url = mysqli_fetch_assoc($sql3); + echo $shorten_url['shorten_url']; + } + } + } + }else{ + echo "$full_url - This is not a valid URL!"; + } +?> \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 00000000..50daa7d2 --- /dev/null +++ b/script.js @@ -0,0 +1,38 @@ +const form = document.querySelector(".wrapper form"), + fullURL = form.querySelector("input"), + shortenBtn = form.querySelector("form button"), + urlsArea = document.querySelector(".urls-area"); + +form.onsubmit = (e) => { + e.preventDefault(); +}; + +shortenBtn.onclick = () => { + let xhr = new XMLHttpRequest(); + xhr.open("POST", "php/url-controll.php", true); + xhr.onload = () => { + if (xhr.readyState == 4 && xhr.status == 200) { + let data = xhr.response; + if (data.length <= 5) { + // Example of setting the shortened URL directly to the list + let domain = "localhost/url/"; + let shortenURL = domain + data; + + // Create a new row for the URL and append it to the list + let newRow = ` +
    +
  • ${shortenURL}
  • +
  • ${fullURL.value}
  • +
  • 0
  • +
  • Delete
  • +
    + `; + urlsArea.insertAdjacentHTML('afterbegin', newRow); + } else { + alert(data); + } + } + }; + let formData = new FormData(form); + xhr.send(formData); +}; diff --git a/style.css b/style.css new file mode 100644 index 00000000..3886dcd2 --- /dev/null +++ b/style.css @@ -0,0 +1,255 @@ +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap'); +*{ + margin: 0; + padding: 0; + box-sizing: border-box; + text-decoration: none; + font-family: 'Poppins', sans-serif; +} +body{ + display: flex; + align-items: center; + justify-content: center; + min-height: 100vh; + background: #20B2AA; + padding: 0 10px; +} +.wrapper{ + background: #fff; + padding: 20px; + width: 800px; + border-radius: 5px; + box-shadow: 0px 5px 10px rgba(0,0,0,0.1); +} +::selection{ + background: rgba(23,162,184,0.3); +} +.wrapper form{ + height: 50px; + width: 100%; + display: flex; + position: relative; + align-items: center; +} +form .url-icon{ + position: absolute; + width: 50px; + text-align: center; + font-size: 23px; + color: #c4c4c4; + pointer-events: none; +} +form input:valid ~ .url-icon{ + color: #20B2AA; +} +form input{ + height: 100%; + width: 100%; + outline: none; + padding: 0 120px 0 45px; + font-size: 20px; + caret-color: #20B2AA; + border: 2px solid #ddd; + border-radius: 5px; + transition: all 0.1s ease; +} +form input:valid{ + border-color: #20B2AA; +} +form input::placeholder{ + color: #c4c4c4; +} +form input:focus::placeholder{ + color: #d9d9d9; +} +form button{ + position: absolute; + right: 6px; + padding: 5px 15px; + font-size: 18px; + border-radius: 5px; + border: none; + outline: none; + background: #20B2AA; + color: #fff; + cursor: pointer; + transition: all 0.3s ease; +} +form button:hover{ + background: #1fada6; +} +.wrapper form button{ + opacity: 0; + pointer-events: none; +} +.wrapper form input:valid ~ button{ + opacity: 1; + pointer-events: auto; +} +.wrapper a{ + color: #000; +} + +.wrapper .statistics{ + margin: 20px 0; + display: flex; + padding-right: 5px; + align-items: center; + justify-content: space-between; +} +.statistics span{ + font-size: 17px; +} +.statistics span span{ + font-weight: 500; +} +.statistics a:hover{ + color: #20B2AA; +} + +.wrapper .urls-area{ + border: 1px solid #ddd; + border-radius: 5px; + margin-bottom: 5px; + max-height: 400px; + overflow-y: scroll; +} +.urls-area::-webkit-scrollbar{ + width: 0px; +} +.urls-area :is(.title, .data){ + display: flex; + width: 100%; + justify-content: space-between; +} +.urls-area li{ + width: 100%; + list-style: none; + border-right: 1px solid #ddd; +} +.urls-area li:last-child{ + border-right: 0px; +} +.urls-area .title li{ + text-align: center; + background: #f2f2f2; + padding: 10px 0; +} +.urls-area .data li{ + padding: 8px 10px; + display: flex; + align-items: center; + justify-content: center; + word-break: break-all; +} +.urls-area .data li:last-child a{ + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: center; +} +.urls-area .data li a:hover{ + color: #20B2AA; + text-decoration: underline; +} +.urls-area .data li:last-child a:hover{ + text-decoration: none; +} +.urls-area .data:nth-child(odd){ + background: #f2f2f2; +} +.urls-area li:nth-child(1){ + max-width: 30%; +} +.urls-area li:nth-child(2){ + max-width: 45%; +} +.urls-area li:nth-child(3){ + max-width: 11%; +} +.urls-area li:nth-child(4){ + max-width: 14%; +} + +.blur-effect{ + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + backdrop-filter: blur(2px); + background: rgba(0,0,0,0.01); + display: none; +} +.popup-box{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) scale(0.9); + background: #fff; + padding: 25px; + max-width: 480px; + width: 100%; + border-radius: 5px; + box-shadow: 0px 5px 10px rgba(0,0,0,0.1); + opacity: 0; + visibility: hidden; + pointer-events: none; + transition: all 0.3s ease; +} +.popup-box.show{ + opacity: 1; + pointer-events: auto; + visibility: visible; + transform: translate(-50%, -50%) scale(1); +} +.popup-box .info-box{ + color: #0f5753; + background: #bef4f1; + border: 1px solid #7de8e3; + padding: 10px; + text-align: center; + font-size: 17px; + border-radius: 5px; +} +.popup-box .info-box.error{ + color: #721c24; + background: #f8d7da; + border-color: #f5c6cb; +} +.popup-box form{ + margin-top: 10px; + position: relative; +} +.popup-box form label{ + font-size: 18px; +} +.popup-box form .copy-icon{ + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-100%); + font-size: 20px; + cursor: pointer; +} +.copy-icon:hover{ + color: #20B2AA; +} +.popup-box form input{ + height: 45px; + padding: 0 35px 0 15px; + margin-top: 3px; + border: 1px solid #ccc; +} +.popup-box form input:focus{ + border-color: #20B2AA; +} +.popup-box form button{ + width: 100%; + height: 45px; + position: relative; + right: 0; + font-size: 20px; + margin-top: 10px; +} \ No newline at end of file diff --git a/unzipper.php b/unzipper.php new file mode 100644 index 00000000..b7b1bbc1 --- /dev/null +++ b/unzipper.php @@ -0,0 +1,422 @@ +prepareExtraction($archive, $destination); +} + +if (isset($_POST['dozip'])) { + $zippath = !empty($_POST['zippath']) ? strip_tags($_POST['zippath']) : '.'; + // Resulting zipfile e.g. zipper--2016-07-23--11-55.zip. + $zipfile = 'zipper-' . date("Y-m-d--H-i") . '.zip'; + Zipper::zipDir($zippath, $zipfile); +} + +$timeend = microtime(TRUE); +$time = round($timeend - $timestart, 4); + +/** + * Class Unzipper + */ +class Unzipper { + public $localdir = '.'; + public $zipfiles = array(); + + public function __construct() { + // Read directory and pick .zip, .rar and .gz files. + if ($dh = opendir($this->localdir)) { + while (($file = readdir($dh)) !== FALSE) { + if (pathinfo($file, PATHINFO_EXTENSION) === 'zip' + || pathinfo($file, PATHINFO_EXTENSION) === 'gz' + || pathinfo($file, PATHINFO_EXTENSION) === 'rar' + ) { + $this->zipfiles[] = $file; + } + } + closedir($dh); + + if (!empty($this->zipfiles)) { + $GLOBALS['status'] = array('info' => '.zip or .gz or .rar files found, ready for extraction'); + } + else { + $GLOBALS['status'] = array('info' => 'No .zip or .gz or rar files found. So only zipping functionality available.'); + } + } + } + + /** + * Prepare and check zipfile for extraction. + * + * @param string $archive + * The archive name including file extension. E.g. my_archive.zip. + * @param string $destination + * The relative destination path where to extract files. + */ + public function prepareExtraction($archive, $destination = '') { + // Determine paths. + if (empty($destination)) { + $extpath = $this->localdir; + } + else { + $extpath = $this->localdir . '/' . $destination; + // Todo: move this to extraction function. + if (!is_dir($extpath)) { + mkdir($extpath); + } + } + // Only local existing archives are allowed to be extracted. + if (in_array($archive, $this->zipfiles)) { + self::extract($archive, $extpath); + } + } + + /** + * Checks file extension and calls suitable extractor functions. + * + * @param string $archive + * The archive name including file extension. E.g. my_archive.zip. + * @param string $destination + * The relative destination path where to extract files. + */ + public static function extract($archive, $destination) { + $ext = pathinfo($archive, PATHINFO_EXTENSION); + switch ($ext) { + case 'zip': + self::extractZipArchive($archive, $destination); + break; + case 'gz': + self::extractGzipFile($archive, $destination); + break; + case 'rar': + self::extractRarArchive($archive, $destination); + break; + } + + } + + /** + * Decompress/extract a zip archive using ZipArchive. + * + * @param $archive + * @param $destination + */ + public static function extractZipArchive($archive, $destination) { + // Check if webserver supports unzipping. + if (!class_exists('ZipArchive')) { + $GLOBALS['status'] = array('error' => 'Error: Your PHP version does not support unzip functionality.'); + return; + } + + $zip = new ZipArchive; + + // Check if archive is readable. + if ($zip->open($archive) === TRUE) { + // Check if destination is writable + if (is_writeable($destination . '/')) { + $zip->extractTo($destination); + $zip->close(); + $GLOBALS['status'] = array('success' => 'Files unzipped successfully'); + } + else { + $GLOBALS['status'] = array('error' => 'Error: Directory not writeable by webserver.'); + } + } + else { + $GLOBALS['status'] = array('error' => 'Error: Cannot read .zip archive.'); + } + } + + /** + * Decompress a .gz File. + * + * @param string $archive + * The archive name including file extension. E.g. my_archive.zip. + * @param string $destination + * The relative destination path where to extract files. + */ + public static function extractGzipFile($archive, $destination) { + // Check if zlib is enabled + if (!function_exists('gzopen')) { + $GLOBALS['status'] = array('error' => 'Error: Your PHP has no zlib support enabled.'); + return; + } + + $filename = pathinfo($archive, PATHINFO_FILENAME); + $gzipped = gzopen($archive, "rb"); + $file = fopen($destination . '/' . $filename, "w"); + + while ($string = gzread($gzipped, 4096)) { + fwrite($file, $string, strlen($string)); + } + gzclose($gzipped); + fclose($file); + + // Check if file was extracted. + if (file_exists($destination . '/' . $filename)) { + $GLOBALS['status'] = array('success' => 'File unzipped successfully.'); + + // If we had a tar.gz file, let's extract that tar file. + if (pathinfo($destination . '/' . $filename, PATHINFO_EXTENSION) == 'tar') { + $phar = new PharData($destination . '/' . $filename); + if ($phar->extractTo($destination)) { + $GLOBALS['status'] = array('success' => 'Extracted tar.gz archive successfully.'); + // Delete .tar. + unlink($destination . '/' . $filename); + } + } + } + else { + $GLOBALS['status'] = array('error' => 'Error unzipping file.'); + } + + } + + /** + * Decompress/extract a Rar archive using RarArchive. + * + * @param string $archive + * The archive name including file extension. E.g. my_archive.zip. + * @param string $destination + * The relative destination path where to extract files. + */ + public static function extractRarArchive($archive, $destination) { + // Check if webserver supports unzipping. + if (!class_exists('RarArchive')) { + $GLOBALS['status'] = array('error' => 'Error: Your PHP version does not support .rar archive functionality. How to install RarArchive'); + return; + } + // Check if archive is readable. + if ($rar = RarArchive::open($archive)) { + // Check if destination is writable + if (is_writeable($destination . '/')) { + $entries = $rar->getEntries(); + foreach ($entries as $entry) { + $entry->extract($destination); + } + $rar->close(); + $GLOBALS['status'] = array('success' => 'Files extracted successfully.'); + } + else { + $GLOBALS['status'] = array('error' => 'Error: Directory not writeable by webserver.'); + } + } + else { + $GLOBALS['status'] = array('error' => 'Error: Cannot read .rar archive.'); + } + } + +} + +/** + * Class Zipper + * + * Copied and slightly modified from http://at2.php.net/manual/en/class.ziparchive.php#110719 + * @author umbalaconmeogia + */ +class Zipper { + /** + * Add files and sub-directories in a folder to zip file. + * + * @param string $folder + * Path to folder that should be zipped. + * + * @param ZipArchive $zipFile + * Zipfile where files end up. + * + * @param int $exclusiveLength + * Number of text to be exclusived from the file path. + */ + private static function folderToZip($folder, &$zipFile, $exclusiveLength) { + $handle = opendir($folder); + + while (FALSE !== $f = readdir($handle)) { + // Check for local/parent path or zipping file itself and skip. + if ($f != '.' && $f != '..' && $f != basename(__FILE__)) { + $filePath = "$folder/$f"; + // Remove prefix from file path before add to zip. + $localPath = substr($filePath, $exclusiveLength); + + if (is_file($filePath)) { + $zipFile->addFile($filePath, $localPath); + } + elseif (is_dir($filePath)) { + // Add sub-directory. + $zipFile->addEmptyDir($localPath); + self::folderToZip($filePath, $zipFile, $exclusiveLength); + } + } + } + closedir($handle); + } + + /** + * Zip a folder (including itself). + * + * Usage: + * Zipper::zipDir('path/to/sourceDir', 'path/to/out.zip'); + * + * @param string $sourcePath + * Relative path of directory to be zipped. + * + * @param string $outZipPath + * Relative path of the resulting output zip file. + */ + public static function zipDir($sourcePath, $outZipPath) { + $pathInfo = pathinfo($sourcePath); + $parentPath = $pathInfo['dirname']; + $dirName = $pathInfo['basename']; + + $z = new ZipArchive(); + $z->open($outZipPath, ZipArchive::CREATE); + $z->addEmptyDir($dirName); + if ($sourcePath == $dirName) { + self::folderToZip($sourcePath, $z, 0); + } + else { + self::folderToZip($sourcePath, $z, strlen("$parentPath/")); + } + $z->close(); + + $GLOBALS['status'] = array('success' => 'Successfully created archive ' . $outZipPath); + } +} +?> + + + + + File Unzipper + Zipper + + + + +

    + Status:
    + Processing Time: seconds +

    +
    +
    +

    Archive Unzipper

    + + + + +

    Enter extraction path without leading or trailing slashes (e.g. "mypath"). If left empty current directory will be used.

    + +
    + +
    +

    Archive Zipper

    + + +

    Enter path to be zipped without leading or trailing slashes (e.g. "zippath"). If left empty current directory will be used.

    + +
    +
    +

    Unzipper version:

    + + diff --git a/url.sql b/url.sql new file mode 100644 index 00000000..f5897987 --- /dev/null +++ b/url.sql @@ -0,0 +1,60 @@ +-- phpMyAdmin SQL Dump +-- version 5.0.4 +-- https://www.phpmyadmin.net/ +-- +-- Host: 127.0.0.1 +-- Generation Time: Mar 18, 2021 at 10:27 AM +-- Server version: 10.4.17-MariaDB +-- PHP Version: 7.3.26 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `urlshortener` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `url` +-- + +CREATE TABLE `url` ( + `id` int(11) NOT NULL, + `shorten_url` varchar(200) NOT NULL, + `full_url` varchar(1000) NOT NULL, + `clicks` int(11) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `url` +-- +ALTER TABLE `url` + ADD PRIMARY KEY (`id`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `url` +-- +ALTER TABLE `url` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=53; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;