浏览代码

First commit

Initial commit
First commit
Update README.md
changed folder name from img to i
Somik 2 年之前
当前提交
c0ab7d6026
共有 5 个文件被更改,包括 392 次插入0 次删除
  1. 5 0
      README.md
  2. 二进制
      i/UC65bn.png
  3. 82 0
      index.php
  4. 154 0
      script.js
  5. 151 0
      style.css

+ 5 - 0
README.md

@@ -0,0 +1,5 @@
+# mini-image-host
+Just a quick image host in PHP
+
+
+<img src="https://raw.githubusercontent.com/somik123/mini-image-host/main/i/UC65bn.png" />

二进制
i/UC65bn.png


+ 82 - 0
index.php

@@ -0,0 +1,82 @@
+<?php
+
+if ($_FILES['file']['error'] === UPLOAD_ERR_OK) {
+    try{
+        $file_name =  $_FILES['file']['name']; //getting file name
+        $tmp_name = $_FILES['file']['tmp_name']; //getting temp_name of file
+
+        $image_info = @getimagesize($tmp_name);
+
+        if($image_info == false)
+            throw new Exception('Please upload valid image file.');
+        
+        $type = $_FILES['file']['type'];     
+        $extensions = array( 'image/jpeg', 'image/png', 'image/gif' );
+        if(!in_array( $type, $extensions ))
+            throw new Exception('Only jpg, jpeg, png, and gif image type supported.');
+        
+        $file_ext = pathinfo($file_name, PATHINFO_EXTENSION);
+        $file_id = rand_str(6);
+        
+        $file_up_path = "i/{$file_id}.{$file_ext}"; 
+        move_uploaded_file($tmp_name, $file_up_path); 
+        
+        $out = array("status"=>"OK","path"=>$file_up_path);
+        echo json_encode($out);
+
+    }
+    catch(Exception $e){
+        $out = array("status"=>"FAIL","msg"=>$e->getMessage());
+        echo json_encode($out);
+    }
+}
+else{
+    $v = "?v=".rand(1111,9999);
+    ?>
+    
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Mini Image Host</title>
+    <link rel="stylesheet" href="style.css<?=$v?>">
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" />
+</head>
+
+<body>
+    <div class="wrapper">
+        <header>Mini Image Host</header>
+        <form action="#">
+            <input class="file-input" type="file" name="file" hidden>
+            <i class="fas fa-cloud-upload-alt"></i>
+            <p>Browse Image to Upload</p>
+        </form>
+        <section class="progress-area"></section>
+        <section class="uploaded-area"></section>
+    </div>
+
+    <script src="script.js<?=$v?>"></script>
+
+    
+
+</body>
+
+</html>
+
+    <?php
+
+}
+
+
+
+function rand_str($length = 10) {
+    $characters = '23456789abcdefghjkmnpqrtuvwxyzABCDEFGHJKLMNPQRTUVWXYZ';
+    $charactersLength = strlen($characters);
+    $randomString = '';
+    for ($i = 0; $i < $length; $i++) {
+        $randomString .= $characters[mt_rand(0, $charactersLength - 1)];
+    }
+    return $randomString;
+}

+ 154 - 0
script.js

@@ -0,0 +1,154 @@
+const form = document.querySelector("form");
+const fileInput = document.querySelector(".file-input");
+const progressArea = document.querySelector(".progress-area");
+const uploadedArea = document.querySelector(".uploaded-area");
+
+// form click event
+form.addEventListener("click", () => {
+    fileInput.click();
+});
+
+fileInput.onchange = ({
+    target
+}) => {
+    let file = target.files[0];
+    if (file) {
+        let fileName = file.name;
+        if (fileName.length >= 12) {
+            let splitName = fileName.split('.');
+            fileName = splitName[0].substring(0, 13) + "... ." + splitName[1];
+        }
+        uploadFile(fileName);
+    }
+}
+
+// file upload function
+function uploadFile(name) {
+    let fileSize;
+
+    let xhr = new XMLHttpRequest(); 
+    xhr.open("POST", "index.php"); 
+
+    xhr.upload.addEventListener("progress", ({
+        loaded,
+        total
+    }) => { 
+        let fileLoaded = Math.floor((loaded / total) * 100); 
+        let fileTotal = Math.floor(total / 1000); 
+
+        (fileTotal < 1024) ? fileSize = fileTotal + " KB": fileSize = (loaded / (1024 * 1024)).toFixed(2) + " MB";
+        let progressHTML = `<li class="row">
+                          <i class="fas fa-file-alt"></i>
+                          <div class="content">
+                            <div class="details">
+                              <span class="name">${name} • Uploading</span>
+                              <span class="percent">${fileLoaded}%</span>
+                            </div>
+                            <div class="progress-bar">
+                              <div class="progress" style="width: ${fileLoaded}%"></div>
+                            </div>
+                          </div>
+                        </li>`;
+        // uploadedArea.innerHTML = ""; //uncomment this line if you don't want to show upload history
+        uploadedArea.classList.add("onprogress");
+        progressArea.innerHTML = progressHTML;
+    });
+    let data = new FormData(form); 
+    xhr.send(data); 
+
+
+    xhr.onload = function() {
+            
+        var api_reply = JSON.parse(xhr.responseText);
+        if (api_reply['status'] == "OK") {
+
+            let url = window.location.href + api_reply['path'];
+
+            progressArea.innerHTML = "";
+            let uploadedHTML = `<li class="row">
+                            <div class="content upload">
+                            <i class="fas fa-file-alt"></i>
+                            <div class="details">
+                                <span class="name">${name} [${fileSize}] <i class="fas fa-check"></i></span>
+                                <span class="small"><a href="${url}">${url}</a></span>
+                            </div>
+                            </div>
+                            <i onclick="copyTextToClipboard('${url}',this)" class="fas fa-clipboard"></i>
+                        </li>`;
+            uploadedArea.classList.remove("onprogress");
+            // uploadedArea.innerHTML = uploadedHTML; //uncomment this line if you don't want to show upload history
+            uploadedArea.insertAdjacentHTML("afterbegin", uploadedHTML); //remove this line if you don't want to show upload history
+
+        } else if (api_reply['status'] == "FAIL") {
+            
+            let error = api_reply['msg'];
+
+            progressArea.innerHTML = "";
+            let uploadedHTML = `<li class="row">
+                            <div class="content upload">
+                            <i class="fas fa-file-alt"></i>
+                            <div class="details">
+                                <span class="name">${name} [${fileSize}]</span>
+                                <span class="small">${error}</a></span>
+                            </div>
+                            </div>
+                            <i class="fas fa-exclamation-triangle"></i>
+                        </li>`;
+            uploadedArea.classList.remove("onprogress");
+            // uploadedArea.innerHTML = uploadedHTML; //uncomment this line if you don't want to show upload history
+            uploadedArea.insertAdjacentHTML("afterbegin", uploadedHTML); //remove this line if you don't want to show upload history
+            
+        }
+    }
+}
+
+
+
+
+
+// Fallback function to copy text to clipboard
+function fallbackCopyTextToClipboard(text) {
+    var textArea = document.createElement("textarea");
+    textArea.value = text;
+
+    // Avoid scrolling to bottom
+    textArea.style.top = "0";
+    textArea.style.left = "0";
+    textArea.style.position = "fixed";
+
+    document.body.appendChild(textArea);
+    textArea.focus();
+    textArea.select();
+
+    try {
+        var successful = document.execCommand('copy');
+        var msg = successful ? 'successful' : 'unsuccessful';
+        console.log('Fallback: Copying text command was ' + msg);
+    } catch (err) {
+        console.error('Fallback: Oops, unable to copy', err);
+    }
+
+    document.body.removeChild(textArea);
+}
+
+
+
+// Main function to copy text to clipboard
+function copyTextToClipboard(text,el) {
+    if (!navigator.clipboard) {
+        fallbackCopyTextToClipboard(text);
+    }
+    else{
+        navigator.clipboard.writeText(text).then(
+            function() {
+                console.log('Async: Copying to clipboard was successful!');
+            }, function(err) {
+                console.error('Async: Could not copy text: ', err);
+            }
+        );
+    }
+    el.className = "fas fa-check";
+    setTimeout(()=> {
+        el.className = "fas fa-clipboard";
+    },3000);
+}

+ 151 - 0
style.css

@@ -0,0 +1,151 @@
+/* Import Google font - Poppins */
+@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap');
+
+* {
+    margin: 0;
+    padding: 0;
+    box-sizing: border-box;
+    font-family: "Poppins", sans-serif;
+}
+
+body {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    min-height: 100vh;
+    background: #6990F2;
+}
+
+::selection {
+    color: #fff;
+    background: #6990F2;
+}
+
+.wrapper {
+    width: 430px;
+    background: #fff;
+    border-radius: 5px;
+    padding: 30px;
+    box-shadow: 7px 7px 12px rgba(0, 0, 0, 0.05);
+}
+
+.wrapper header {
+    color: #6990F2;
+    font-size: 27px;
+    font-weight: 600;
+    text-align: center;
+}
+
+.wrapper form {
+    height: 167px;
+    display: flex;
+    cursor: pointer;
+    margin: 30px 0;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    border-radius: 5px;
+    border: 2px dashed #6990F2;
+}
+
+form :where(i, p) {
+    color: #6990F2;
+}
+
+form i {
+    font-size: 50px;
+}
+
+form p {
+    margin-top: 15px;
+    font-size: 16px;
+}
+
+section .row {
+    margin-bottom: 10px;
+    background: #E9F0FF;
+    list-style: none;
+    padding: 15px 20px;
+    border-radius: 5px;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+}
+
+section .row i {
+    color: #6990F2;
+    font-size: 30px;
+}
+
+section .details span {
+    font-size: 14px;
+}
+
+.progress-area .row .content {
+    width: 100%;
+    margin-left: 15px;
+}
+
+.progress-area .details {
+    display: flex;
+    align-items: center;
+    margin-bottom: 7px;
+    justify-content: space-between;
+}
+
+.progress-area .content .progress-bar {
+    height: 6px;
+    width: 100%;
+    margin-bottom: 4px;
+    background: #fff;
+    border-radius: 30px;
+}
+
+.content .progress-bar .progress {
+    height: 100%;
+    width: 0%;
+    background: #6990F2;
+    border-radius: inherit;
+}
+
+.uploaded-area {
+    max-height: 232px;
+    overflow-y: scroll;
+}
+
+.uploaded-area.onprogress {
+    max-height: 150px;
+}
+
+.uploaded-area::-webkit-scrollbar {
+    width: 0px;
+}
+
+.uploaded-area .row .content {
+    display: flex;
+    align-items: center;
+}
+
+.uploaded-area .row .details {
+    display: flex;
+    margin-left: 15px;
+    flex-direction: column;
+}
+
+.uploaded-area .row .details .small {
+    color: #0e01be;
+    font-size: 11px;
+}
+
+.uploaded-area i.fa-check {
+    font-size: 16px;
+}
+
+.uploaded-area i.fa-clipboard {
+    font-size: 24px;
+    cursor: pointer;
+}
+
+.uploaded-area i.fa-exclamation-triangle {
+    font-size: 24px;
+}