New upload manager to handle images and attachments
authorx2003bruneau <x2003bruneau@839d8a87-29fc-0310-9880-83ba4fa771e5>
Tue, 6 Mar 2007 09:16:42 +0000 (09:16 +0000)
committerx2003bruneau <x2003bruneau@839d8a87-29fc-0310-9880-83ba4fa771e5>
Tue, 6 Mar 2007 09:16:42 +0000 (09:16 +0000)
git-svn-id: svn+ssh://murphy/home/svn/platal/trunk@1553 839d8a87-29fc-0310-9880-83ba4fa771e5

ChangeLog
classes/platalpage.php
classes/plupload.php [new file with mode: 0644]
include/platal.inc.php
include/validations/photos.inc.php
modules/profile.php

index a28925b..af87d45 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,7 @@ New:
     * Core:
         - UTF-8                                                            -FRU
         - New Backtrace tool                                               -FRU
+        - New Upload manager                                               -FRU
 
     * Events:
         - #643: Sort menu                                                  -FRU
index 84a0a91..0fe8ec6 100644 (file)
@@ -28,11 +28,6 @@ class PlatalPage extends Smarty
     private $_errors;
     private $_failure;
 
-    // defaults
-    var $caching          = false;
-    var $config_overwrite = false;
-    var $use_sub_dirs     = false;
-
     // {{{ function PlatalPage()
 
     public function __construct($tpl, $type = SKINNED)
@@ -41,6 +36,9 @@ class PlatalPage extends Smarty
 
         global $globals;
 
+        $this->caching       = false;
+        $this->config_overwrite = false;
+        $this->use_sub_dirs  = false;
         $this->template_dir  = $globals->spoolroot."/templates/";
         $this->compile_dir   = $globals->spoolroot."/spool/templates_c/";
         array_unshift($this->plugins_dir, $globals->spoolroot."/plugins/");
@@ -227,7 +225,7 @@ function escape_html($string)
 {
     if (is_string($string)) {
        $transtbl = Array('<' => '&lt;', '>' => '&gt;', '"' => '&quot;', '\'' => '&#39;');
-       return preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,4};)/", "&amp;" , strtr($string, $transtbl));
+       return preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,4};)/u", "&amp;", strtr(pl_entities($string), $transtbl));
     } else {
        return $string;
     }
@@ -265,8 +263,8 @@ function at_to_globals($tpl_source, &$smarty)
 function trimwhitespace($source, &$smarty)
 {
     $tags = '(script|pre|textarea)';
-    preg_match_all("!<$tags.*?>.*?</$tags>!ius", $source, $tagsmatches);
-    $source = preg_replace("!<$tags.*?>.*?</$tags>!ius", "&&&tags&&&", $source);
+    preg_match_all("!<$tags.*?>.*?</(\\1)>!ius", $source, $tagsmatches);
+    $source = preg_replace("!<$tags.*?>.*?</(\\1)>!ius", "&&&tags&&&", $source);
 
     // remove all leading spaces, tabs and carriage returns NOT
     // preceeded by a php close tag.
@@ -301,19 +299,19 @@ function hide_emails($source, &$smarty)
 {
     //prevent email replacement in <script> and <textarea>
     $tags = '(script|textarea|select)';
-    preg_match_all("!<$tags.*?>.*?</$tags>!ius", $source, $tagsmatches);
-    $source = preg_replace("!<$tags.*?>.*?</$tags>!ius", "&&&tags&&&", $source);
+    preg_match_all("!<$tags.*?>.*?</(\\1)>!ius", $source, $tagsmatches);
+    $source = preg_replace("!<$tags.*?>.*?</(\\1)>!ius", "&&&tags&&&", $source);
 
     //catch all emails in <a href="mailto:...">
     preg_match_all("!<a[^>]+href=[\"'][^\"']*[-a-z0-9+_.]+@[-a-z0-9_.]+[^\"']*[\"'].*?>.*?</a>!ius", $source, $ahref);
     $source = preg_replace("!<a[^>]+href=[\"'][^\"']*[-a-z0-9+_.]+@[-a-z0-9_.]+[^\"']*[\"'].*?>.*?</a>!ius", '&&&ahref&&&', $source);
 
     //prevant replacement in tag attributes
-    preg_match_all("!<[^>]+[-a-z0-9_+.]+@[-a-z0-9_.]+.+?>!is", $source, $misc);
-    $source = preg_replace("!<[^>]+[-a-z0-9_+.]+@[-a-z0-9_.]+.+?>!is", '&&&misc&&&', $source);
+    preg_match_all("!<[^>]+[-a-z0-9_+.]+@[-a-z0-9_.]+.+?>!ius", $source, $misc);
+    $source = preg_replace("!<[^>]+[-a-z0-9_+.]+@[-a-z0-9_.]+.+?>!ius", '&&&misc&&&', $source);
 
     //catch !
-    $source = preg_replace('!([-a-z0-9_+.]+@[-a-z0-9_.]+)!ie', '_hide_email("\1")', $source); 
+    $source = preg_replace('!([-a-z0-9_+.]+@[-a-z0-9_.]+)!iue', '_hide_email("\1")', $source); 
     $source = preg_replace('!&&&ahref&&&!e', '_hide_email(array_shift($ahref[0]))', $source);
 
     // restore data
diff --git a/classes/plupload.php b/classes/plupload.php
new file mode 100644 (file)
index 0000000..d5f428f
--- /dev/null
@@ -0,0 +1,242 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2007 Polytechnique.org                              *
+ *  http://opensource.polytechnique.org/                                   *
+ *                                                                         *
+ *  This program is free software; you can redistribute it and/or modify   *
+ *  it under the terms of the GNU General Public License as published by   *
+ *  the Free Software Foundation; either version 2 of the License, or      *
+ *  (at your option) any later version.                                    *
+ *                                                                         *
+ *  This program is distributed in the hope that it will be useful,        *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *  GNU General Public License for more details.                           *
+ *                                                                         *
+ *  You should have received a copy of the GNU General Public License      *
+ *  along with this program; if not, write to the Free Software            *
+ *  Foundation, Inc.,                                                      *
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
+ ***************************************************************************/
+
+/** Class to store per user and per category files
+ */
+class PlUpload
+{
+    private $forlife;
+    private $category;
+    private $file_id;
+
+    private $filename;
+    private $type;
+
+    /** For images
+     */
+    private $x;
+    private $y;
+
+    public function __construct($forlife, $category, $filename = null)
+    {
+        $this->file_id  = $filename;
+        $this->category = $category;
+        $this->forlife  = $forlife;
+        $this->filename = $this->makeFilename($this->file_id);
+        $this->checkContentType();
+    }
+
+    private function makeFilename($file_id)
+    {
+        global $globals;
+        $filename = $globals->spoolroot . '/spool/uploads/temp/';
+        if (!file_exists($filename)) {
+            if (!mkdir($filename)) {
+                trigger_error('can\'t create upload directory: ' . $filename, E_USER_ERROR);
+            }
+        }
+        $filename .= $this->forlife . '-' . $this->category;
+        if ($file_id) {
+            $filename .= '-' . $file_id;
+        }
+        return $filename;
+    }
+
+    private function checkContentType()
+    {
+        if ($this->exists()) {
+            $this->type = trim(mime_content_type($this->filename));
+        }
+    }
+
+    public function upload(array &$file)
+    {
+        if (!is_uploaded_file($file['tmp_name'])) {
+            return false;
+        } else if (!move_uploaded_file($file['tmp_name'], $this->filename)) {
+            return false;
+        }
+        $this->checkContentType(); 
+        return true;
+    }
+
+    public function copyFrom($filename)
+    {
+        if (!copy($filename, $this->filename)) {
+            return false;
+        }
+        $this->checkContentType();
+        return true;
+    }
+
+    public function download($url)
+    {
+        $data = file_get_contents($url);
+        if (!$data) {
+            return false;
+        }
+        if (!file_put_contents($this->filename, $data)) {
+            return false;
+        }
+        $this->checkContentType();
+        return true;
+    }
+
+    static public function &get(array &$file, $forlife, $category, $uniq = false)
+    {
+        $upload = new PlUpload($forlife, $category, $uniq ? null : $file['name']);
+        if (!$upload->upload($file)) {
+            $upload = null;
+        }
+        return $upload;
+    }
+
+    public function rm()
+    {
+        @unlink($this->filename);
+        clearstatcache();
+    }
+
+    public function rename($fn)
+    {
+        if (!$this->file_id) {
+            return false;
+        }
+        $filename = $this->makeFilename($fn);
+        if (rename($this->filename)) {
+            $this->filename = $filename;
+            $this->file_id  = $fn;
+            clearstatcache();
+            return true;
+        }
+        return false;
+    }
+
+    public function exists()
+    {
+        return file_exists($this->filename);
+    }
+
+    static public function listFiles($forlife = '*', $category = '*', $basename = false)
+    {
+        global $globals;
+        $filename = $globals->spoolroot . '/spool/uploads/temp/';
+        $filename .= $forlife . '-' . $category;
+        $files = glob($filename);
+        if ($basename) {
+            array_walk($files, 'basename');
+        }
+        return $files;
+    }
+
+    static public function clear($user = '*', $category = '*')
+    {
+        $files = PlUpload::listFiles($user, $category, false);
+        array_walk($files, 'unlink');
+    }
+
+    public function contentType()
+    {
+        return $this->type;
+    }
+
+    public function imageInfo()
+    {
+        return getimagesize($this->filename);
+    }
+
+    public function resizeImage($max_x = -1, $max_y = -1, $min_x = 0, $min_y = 0, $maxsize = -1)
+    {
+        if (!$this->exists() || strpos($this->type, 'image/') !== 0) {
+            trigger_error('not an image', E_USER_NOTICE);
+            return false;
+        }
+        $image_infos = $this->imageInfo();
+        if (empty($image_infos)) {
+            trigger_error('invalid image', E_USER_NOTICE);
+            return false;
+        }
+        list($this->x, $this->y, $mimetype) = $image_infos;
+        if ($mimetype < 1 || $mimetype > 3) { // 1 - gif, 2 - jpeg, 3 - png
+            trigger_error('unknown image type', E_USER_NOTICE);
+            return false;
+        }
+        if ($max_x == -1) {
+            $max_x = $this->x;
+        }
+        if ($max_y == -1) {
+            $max_y = $this->y;
+        }
+        if ($maxsize == -1) {
+            $maxsize = filesize($this->filename);
+        }
+        if (filesize($this->filename) > $maxsize || $this->x > $max_x || $this->y > $max_y
+                                                 || $this->x < $min_x || $this->y < $min_y) {
+            $img = imagecreatefromstring(file_get_contents($this->filename));
+            if (!$img) {
+                trigger_error('too large image, can\'t be resized', E_USER_NOTICE);
+                return false;
+            }
+
+            $nx = $this->x;
+            $ny = $this->y;
+            if ($nx > $max_x) {
+                $ny = intval($ny*$max_x/$nx);
+                $nx = $max_x;
+            }
+            if ($ny > $max_y) {
+                $nx = intval($nx*$max_y/$ny);
+                $ny = $max_y;
+            }
+            if ($nx < $min_x) {
+                $ny = intval($ny*$min_x/$nx);
+                $nx = $min_x;
+            }
+            if ($ny < $min_y) {
+                $nx = intval($nx * $min_y/$ny);
+                $ny = $min_y;
+            }
+
+            $comp = 90;
+            do {
+                $img2 = imagecreatetruecolor($nx, $ny);
+                imagecopyresampled($img2, $img, 0, 0, 0, 0, $nx, $ny, $this->x, $this->y);
+                imagejpeg($img2, $this->filename, $comp);
+                $comp --;
+                clearstatcache();
+            } while (filesize($this->filename) > $maxsize && $comp > 0);
+            $this->type = 'image/jpeg';
+            $this->x    = $nx;
+            $this->y    = $ny;
+        }
+        return true;
+    }
+
+    public function getContents()
+    {
+        if ($this->exists()) {
+            return file_get_contents($this->filename);
+        }
+        return null;
+    }
+}
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
index b7142d4..42e776a 100644 (file)
@@ -21,8 +21,6 @@
 
 $TIME_BEGIN = microtime(true);
 
-date_default_timezone_set('Europe/Paris');
-
 define('AUTH_PUBLIC', 0);
 define('AUTH_COOKIE', 1);
 define('AUTH_MDP',    2);
index f158f28..9010dea 100644 (file)
@@ -43,74 +43,26 @@ class PhotoReq extends Validate
     // }}}
     // {{{ constructor
 
-    public function __construct($_uid, $_data, $_stamp=0)
+    public function __construct($_uid, PlUpload &$upload, $_stamp=0)
     {
-        $this->Validate($_uid, true, 'photo', $_stamp);
-        $this->valid = $this->_get_image($_data);
+        parent::__construct($_uid, true, 'photo', $_stamp);
+        $this->read($upload);
     }
 
     // }}}
-    // {{{ function _get_image()
+    // {{{ function read
 
-    private function _get_image($_data)
+    private function read(PlUpload &$upload)
     {
-        global $page;
-
-        VarStream::init();
-
-        // calcul de la taille de l'image
-        $GLOBALS['photoreq'] = $_data;
-        $image_infos = getimagesize('var://photoreq');
-        unset ($GLOBALS['photoreq']);
-
-        if (empty($image_infos)) {
-            $page->trig("Image invalide");
-            return false;
-        }
-        list($this->x, $this->y, $this->mimetype) = $image_infos;
-
-        switch ($this->mimetype) {
-        case 1: $this->mimetype = "gif";    break;
-        case 2: $this->mimetype = "jpeg";   break;
-        case 3: $this->mimetype = "png";    break;
-        default:
-            $page->trig("Type d'image invalide");
-            return false;
-        }
-
-        if (strlen($_data) > SIZE_MAX)  {
-            $img = imagecreatefromstring($_data);
-            if (!$img) {
-                $page->trig("image trop grande et impossible à retailler automatiquement");
-                return false;
-            }
-
-            $nx = $x = imagesx($img);
-            $ny = $y = imagesy($img);
-
-            if ($nx > 240) { $ny = intval($ny*240/$nx); $nx = 240; }
-            if ($ny > 300) { $ny = intval($nx*300/$nx); $ny = 300; }
-            if ($nx < 160) { $ny = intval($ny*160/$nx); $nx = 160; }
-
-            $comp = '90';
-            $file = tempnam('/tmp', 'photo');
-
-            while (strlen($_data) > SIZE_MAX) {
-                $img2  = imagecreatetruecolor($nx, $ny);
-                imagecopyresampled($img2, $img, 0, 0, 0, 0, $nx, $ny, $x, $y);
-                imagejpeg($img2, $file, $comp);
-                $_data = file_get_contents($file);
-                $this->mimetype = 'jpeg';
-
-                $comp --;
-            }
-
-            unlink($file);
+        $this->valid = $upload->resizeImage(240, 300, 160, 0, SIZE_MAX); 
+        if (!$this->valid) {
+            $this->trig('Le fichier que tu as transmis n\'est pas une image valide, ou est trop gros pour être traité');
         }
-        $this->data = $_data;
-        return true;
+        $this->data = $upload->getContents();
+        list($this->x, $this->y, $this->mimetype) = $upload->imageInfo();
+        $upload->rm();
     }
-
+    
     // }}}
     // {{{ function isValid()
 
@@ -148,17 +100,16 @@ class PhotoReq extends Validate
 
     protected function handle_editor()
     {
-        if (isset($_FILES['userfile']['tmp_name'])) {
-            $file = $_FILES['userfile']['tmp_name'];
-            if ($data = file_get_contents($file)) {
-                if ($this->valid = $this->_get_image($data)) {
-                    return true;
-                }
-            } else {
-                $page->trig('Fichier inexistant ou vide');
+        if (isset($_FILES['userfile'])) {
+            $upload =& PlUpload::get($_FILES['userfile'], S::v('forlife'), 'photo');
+            if (!$upload) {
+                $this->trig('Une erreur est survenue lors du téléchargement du fichier');
+                return false;
             }
+            $this->read($upload);
+            return $this->valid;
         }
-        return false; 
+        return false;
     }
 
     // }}}
index b826f5a..e6de2ca 100644 (file)
@@ -124,29 +124,23 @@ class ProfileModule extends PLModule
                     .'/'.S::v('forlife').'.jpg';
 
         if (Env::has('upload')) {
-            if (isset($_FILES['userfile']['tmp_name']) && !is_uploaded_file($_FILES['userfile']['tmp_name'])) {
-                $page->trig('Une erreur s\'est produite lors du transfert du fichier');
-            } elseif (strpos(trim(mime_content_type($_FILES['userfile']['tmp_name'])), 'image/') !== 0) {
-                $page->trig('Le fichier que tu as transmis n\'est pas une image.');
-            } else {            
-                $file = is_uploaded_file($_FILES['userfile']['tmp_name'])
-                        ? $_FILES['userfile']['tmp_name']
-                        : Env::v('photo');
-                if ($data = file_get_contents($file)) {
-                    $myphoto = new PhotoReq(S::v('uid'), $data);
-                    if ($myphoto->isValid()) {
-                        $myphoto->submit();
-                    }
-                } else {
-                    $page->trig('Fichier inexistant ou vide');
+            $upload = new PlUpload(S::v('forlife'), 'photo');
+            if (!$upload->upload($_FILES['userfile']) && !$upload->download(Env::v('photo'))) {
+                $page->trig('Une erreur est survenue lors du téléchargement du fichier');
+            } else {
+                $myphoto = new PhotoReq(S::v('uid'), $upload);
+                if ($myphoto->isValid()) {
+                    $myphoto->submit();
                 }
             }
         } elseif (Env::has('trombi')) {
-            $myphoto = new PhotoReq(S::v('uid'),
-                                    file_get_contents($trombi_x));
-            if ($myphoto->isValid()) {
-                $myphoto->commit();
-                $myphoto->clean();
+            $upload = new PlUpload(S::v('forlife'), 'photo');
+            if ($upload->copyFrom($trombi_x)) {
+                $myphoto = new PhotoReq(S::v('uid'), $upload);
+                if ($myphoto->isValid()) {
+                    $myphoto->commit();
+                    $myphoto->clean();
+                }
             }
         } elseif (Env::v('suppr')) {
             XDB::execute('DELETE FROM photo WHERE uid = {?}',
@@ -161,8 +155,8 @@ class ProfileModule extends PLModule
         }
 
         $sql = XDB::query('SELECT COUNT(*) FROM requests
-                                      WHERE user_id={?} AND type="photo"',
-                                    S::v('uid'));
+                            WHERE user_id={?} AND type="photo"',
+                          S::v('uid'));
         $page->assign('submited', $sql->fetchOneCell());
         $page->assign('has_trombi_x', file_exists($trombi_x));
     }