Explorar o código

[add] post form (missing resize on receive)
[add] image storage as base64 encoded jpeg
[add] image url handling
[add] spoil security

isundil %!s(int64=9) %!d(string=hai) anos
pai
achega
7a93615507
Modificáronse 8 ficheiros con 183 adicións e 19 borrados
  1. 57 5
      src/Flammenkuchen.php
  2. 53 0
      src/Poster.php
  3. 38 10
      src/Router.php
  4. 3 1
      src/templates/bonjour.php
  5. 1 1
      src/templates/lost.php
  6. 8 0
      src/templates/post.php
  7. 23 2
      www/index.php
  8. 0 0
      www/js/scripts_post.js

+ 57 - 5
src/Flammenkuchen.php

@@ -6,11 +6,29 @@ class Flammenkuchen
     private $descr;
     private $img;
 
-    public function __construct($data)
+    private function __construct()
+    { }
+
+    public static function fromJson($data)
     {
-        $this->title = $data->title;
-        $this->descr = $data->desc;
-        $this->img = $data->img;
+        $result = new Flammenkuchen();
+
+        $result->title = $data->title;
+        $result->descr = $data->desc;
+        $result->img = imagecreatefromstring(base64_decode($data->img));
+
+        return $result;
+    }
+
+    public static function fromForm($title, $desc)
+    {
+        $result = new Flammenkuchen();
+
+        $result->title = htmlentities($title);
+        $result->descr = htmlentities($desc);
+        $result->img = null;
+
+        return $result;
     }
 
     public function getTitle()
@@ -23,9 +41,43 @@ class Flammenkuchen
         return $this->descr;
     }
 
-    public function getImageB64()
+    public function getImageJpeg()
     {
         return $this->img;
     }
+
+    public function imageMd5()
+    {
+        ob_start();
+        imagejpeg($this->img);
+        return md5(base64_encode(ob_get_clean()));
+    }
+
+    public function toJson()
+    {
+        ob_start();
+        imagejpeg($this->img);
+        $imageEncoded = base64_encode(ob_get_clean());
+
+        return json_encode(array(
+            "title" => $this->title
+            ,"desc" => $this->descr
+            ,"img"  => $imageEncoded
+        ));
+    }
+
+    public function createImage($type, $tmpFile)
+    {
+        if ($type == "image/png")
+            $this->img = imagecreatefrompng($tmpFile);
+        else if ($type == "image/jpg" || $type == "image/jpeg")
+            $this->img = imagecreatefromjpeg($tmpFile);
+        else
+        {
+            die("no such type" .$type);
+            return false;
+        }
+        return $this->img !== false;
+    }
 }
 

+ 53 - 0
src/Poster.php

@@ -0,0 +1,53 @@
+<?php
+
+require_once ("Flammenkuchen.php");
+
+class Poster
+{
+    public function __construct()
+    {
+    }
+
+    public function work()
+    {
+        $this->data = Flammenkuchen::fromForm($_POST["title"], $_POST["descr"]);
+        foreach ($_FILES as $f)
+        {
+            if (!$this->data->createImage($f["type"], $f["tmp_name"]))
+                die ("Invalid image format");
+            //TODO check unicity using cache
+            file_put_contents("../data/" .$this->getNextAvailableDay() .".json", $this->data->toJson());
+            break;
+        }
+    }
+
+    private function getNextAvailableDay()
+    {
+        //TODO use cache
+        $max = (int) (new \Datetime())->format("ymd");
+        $datadir = opendir("../data/");
+        while (($file = readdir($datadir)) !== false)
+        {
+            if (is_dir("../data/".$file)
+                || strlen($file) != 11
+                || substr($file, 6) !== ".json")
+                continue;
+
+            $current = (int) substr($file, 0, 6);
+
+            if ($current > $max)
+                $max = $current;
+        }
+        closedir($datadir);
+
+        $max = (string) $max;
+        $year = substr($max, 0, 2);
+        $month = substr($max, 2, 2);
+        $day = substr($max, 4, 2);
+        $date = new \DateTime();
+        $date->setDate($year +2000, $month, $day);
+        $date->add(new \DateInterval("P1D"));
+        return ($date->format("ymd"));
+    }
+}
+

+ 38 - 10
src/Router.php

@@ -12,43 +12,56 @@ class Router
 
     function __construct()
     {
-        $this->request = $_SERVER["REQUEST_URI"];
-        $this->data = null;
+        $request = $_SERVER["REQUEST_URI"];
+        $this->data = $this->requestingDate = null;
 
-        if ($this->request[0] == '/')
-            $this->request = substr($this->request, 1);
+        if ($request[0] == '/')
+            $request = substr($request, 1);
+        $this->request = $request;
 
-        if ($this->request == "")
+        if (substr($request, -4) == ".jpg")
+            $request = substr($request, 0, -4);
+
+        if ($request == "")
             $this->requestingDate = $this->checkFileExists($this->LATEST);
-        else if (strlen($this->request) == 6)
+        else if (strlen($request) == 6)
         {
             $isNumeric = true;
 
             for ($i =0; $i < 6; $i++)
             {
-                if (!is_numeric($this->request[$i]))
+                if (!is_numeric($request[$i]))
                 {
                     $isNumeric = false;
                     break;
                 }
             }
             if ($isNumeric)
-                $this->requestingDate = $this->checkFileExists($this->request);
+                $this->requestingDate = $this->checkFileExists($request);
         }
     }
 
+    public function getImageForRequest()
+    {
+        if ($this->requestingDate === null)
+            return "";
+        return "/{$this->requestingDate}.jpg";
+    }
+
     private function checkFileExists($yymmdd)
     {
+        $now = (int) (new \Datetime())->format("ymd");
         if ($yymmdd != $this->LATEST)
         {
             // TODO use index cache
+            if ((int) $yymmdd > $now) // Anti spoil
+                return null;
             if (file_exists("../data/${yymmdd}.json"))
                 return $yymmdd;
             return null;
         }
         else
         {
-            $now = (int) (new \Datetime())->format("ymd");
             $min = 0;
 
             // obvious today-is-the-day
@@ -76,6 +89,21 @@ class Router
         }
     }
 
+    public function isRequestingImage()
+    {
+        return (substr($this->request, -4) === ".jpg");
+    }
+
+    public function isGetRequest()
+    {
+        return $_SERVER["REQUEST_METHOD"] === "GET";
+    }
+
+    public function isPostUri()
+    {
+        return $this->request == "post";
+    }
+
     public function isLost()
     {
         if ($this->requestingDate === null)
@@ -96,7 +124,7 @@ class Router
     {
         $req = $this->requestingDate;
 
-        return new Flammenkuchen(json_decode(file_get_contents("../data/${req}.json")));
+        return Flammenkuchen::fromJson(json_decode(file_get_contents("../data/${req}.json")));
     }
 }
 

+ 3 - 1
src/templates/bonjour.php

@@ -1,4 +1,6 @@
-<?php include ("./header.php"); ?>
+<?php include ("header.php"); ?>
 <title>Bonjour Flammenkuchen !</title></head><body>
 <?php var_dump($data); ?>
+<?php var_dump($router); ?>
+<img src="<?php echo $router->getImageForRequest(); ?>" alt="<?php echo $data->getTitle(); ?>" />
 </body></html>

+ 1 - 1
src/templates/lost.php

@@ -1,4 +1,4 @@
-<?php header("404 Not Found"); include ("./header.php"); ?>
+<?php header("http/1.0 404 Not Found"); include ("header.php"); ?>
     <title>Not found</title>
 </head><body>
     <h1>Oops</h1>

+ 8 - 0
src/templates/post.php

@@ -0,0 +1,8 @@
+<?php require ("header.php"); ?><title>Share a flamm</title><script src="/js/scripts_post.js"></script></head><body>
+<form method="POST" action="/post" enctype="multipart/form-data">
+    <input type="text" name="title"/>
+    <input type="text" name="descr"/>
+    <input type="file" name="img" />
+    <input type="submit">
+</form>
+</body></html>

+ 23 - 2
www/index.php

@@ -1,14 +1,35 @@
 <?php
 
 require_once("../src/Router.php");
+require_once("../src/Poster.php");
 
 $router = new Router();
 
-    $data = $router->getData();
-if ($router->isLost())
+if ($router->isPostUri())
+{
+    if ($router->isGetRequest())
+        include ("../src/templates/post.php");
+    else
+    {
+        $post = new Poster();
+        if ($post->work() !== false)
+            header("http/1.0 201 Created");
+        else
+            header("http/1.0 409 Conflict");
+        die;
+    }
+}
+else if ($router->isLost())
     include("../src/templates/lost.php");
+else if ($router->isRequestingImage())
+{
+    header("Content-Type: image/jpeg");
+    imagejpeg($router->getData()->getImageJpeg());
+    die;
+}
 else
 {
+    $data = $router->getData();
     include("../src/templates/bonjour.php");
 }
 

+ 0 - 0
www/js/scripts_post.js