Dotclear

source: inc/core/class.dc.media.php @ 3730:5c45a5df9a59

Revision 3730:5c45a5df9a59, 46.7 KB checked in by franck <carnet.franck.paul@…>, 7 years ago (diff)

Code formatting (PSR-2)

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
7# Licensed under the GPL version 2.0 license.
8# See LICENSE file or
9# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10#
11# -- END LICENSE BLOCK -----------------------------------------
12if (!defined('DC_RC_PATH')) {return;}
13
14/**
15@ingroup DC_CORE
16@brief Dotclear media manage
17
18This class handles Dotclear media items.
19 */
20class dcMedia extends filemanager
21{
22    protected $core;  ///< <b>dcCore</b> dcCore instance
23    protected $con;   ///< <b>connection</b> Database connection
24    protected $table; ///< <b>string</b> Media table name
25    protected $type;  ///< <b>string</b> Media type filter
26    protected $postmedia;
27    protected $file_sort = 'name-asc';
28
29    protected $file_handler = array(); ///< <b>array</b> Array of callbacks
30
31    public $thumb_tp       = '%s/.%s_%s.jpg'; ///< <b>string</b> Thumbnail file pattern
32    public $thumb_tp_alpha = '%s/.%s_%s.png'; ///< <b>string</b> Thumbnail file pattern (with alpha layer)
33
34    /**
35    <b>array</b> Tubmnail sizes:
36    - m: medium image
37    - s: small image
38    - t: thumbnail image
39    - sq: square image
40     */
41    public $thumb_sizes = array(
42        'm'  => array(448, 'ratio', 'medium'),
43        's'  => array(240, 'ratio', 'small'),
44        't'  => array(100, 'ratio', 'thumbnail'),
45        'sq' => array(48, 'crop', 'square')
46    );
47
48    public $icon_img = 'images/media/%s.png'; ///< <b>string</b> Icon file pattern
49
50    /**
51    Object constructor.
52
53    @param    core        <b>dcCore</b>        dcCore instance
54    @param    type        <b>string</b>        Media type filter
55     */
56    public function __construct($core, $type = '')
57    {
58        $this->core      = &$core;
59        $this->con       = &$core->con;
60        $this->postmedia = new dcPostMedia($core);
61
62        if ($this->core->blog == null) {
63            throw new Exception(__('No blog defined.'));
64        }
65
66        $this->table = $this->core->prefix . 'media';
67        $root        = $this->core->blog->public_path;
68
69        if (preg_match('#^http(s)?://#', $this->core->blog->settings->system->public_url)) {
70            $root_url = rawurldecode($this->core->blog->settings->system->public_url);
71        } else {
72            $root_url = rawurldecode($this->core->blog->host . path::clean($this->core->blog->settings->system->public_url));
73        }
74
75        if (!is_dir($root)) {
76            # Check public directory
77            if ($core->auth->isSuperAdmin()) {
78                throw new Exception(__("There is no writable directory /public/ at the location set in about:config \"public_path\". You must create this directory with sufficient rights (or change this setting)."));
79            } else {
80                throw new Exception(__("There is no writable root directory for the media manager. You should contact your administrator."));
81            }
82        }
83
84        $this->type = $type;
85
86        parent::__construct($root, $root_url);
87        $this->chdir('');
88
89        $this->path = $this->core->blog->settings->system->public_path;
90
91        $this->addExclusion(DC_RC_PATH);
92        $this->addExclusion(dirname(__FILE__) . '/../');
93
94        $this->exclude_pattern = $core->blog->settings->system->media_exclusion;
95
96        # Event handlers
97        $this->addFileHandler('image/jpeg', 'create', array($this, 'imageThumbCreate'));
98        $this->addFileHandler('image/png', 'create', array($this, 'imageThumbCreate'));
99        $this->addFileHandler('image/gif', 'create', array($this, 'imageThumbCreate'));
100
101        $this->addFileHandler('image/png', 'update', array($this, 'imageThumbUpdate'));
102        $this->addFileHandler('image/jpeg', 'update', array($this, 'imageThumbUpdate'));
103        $this->addFileHandler('image/gif', 'update', array($this, 'imageThumbUpdate'));
104
105        $this->addFileHandler('image/png', 'remove', array($this, 'imageThumbRemove'));
106        $this->addFileHandler('image/jpeg', 'remove', array($this, 'imageThumbRemove'));
107        $this->addFileHandler('image/gif', 'remove', array($this, 'imageThumbRemove'));
108
109        $this->addFileHandler('image/jpeg', 'create', array($this, 'imageMetaCreate'));
110
111        $this->addFileHandler('image/jpeg', 'recreate', array($this, 'imageThumbCreate'));
112        $this->addFileHandler('image/png', 'recreate', array($this, 'imageThumbCreate'));
113        $this->addFileHandler('image/gif', 'recreate', array($this, 'imageThumbCreate'));
114
115        $this->addFileHandler('image/jpeg', 'recreate', array($this, 'imageThumbCreate'));
116        $this->addFileHandler('image/png', 'recreate', array($this, 'imageThumbCreate'));
117        $this->addFileHandler('image/gif', 'recreate', array($this, 'imageThumbCreate'));
118
119        # Thumbnails sizes
120        $this->thumb_sizes['m'][0] = abs($core->blog->settings->system->media_img_m_size);
121        $this->thumb_sizes['s'][0] = abs($core->blog->settings->system->media_img_s_size);
122        $this->thumb_sizes['t'][0] = abs($core->blog->settings->system->media_img_t_size);
123
124        # Thumbnails sizes names
125        $this->thumb_sizes['m'][2]  = __($this->thumb_sizes['m'][2]);
126        $this->thumb_sizes['s'][2]  = __($this->thumb_sizes['s'][2]);
127        $this->thumb_sizes['t'][2]  = __($this->thumb_sizes['t'][2]);
128        $this->thumb_sizes['sq'][2] = __($this->thumb_sizes['sq'][2]);
129
130        # --BEHAVIOR-- coreMediaConstruct
131        $this->core->callBehavior('coreMediaConstruct', $this);
132    }
133
134    /**
135    Changes working directory.
136
137    @param    dir        <b>string</b>        Directory name.
138     */
139    public function chdir($dir)
140    {
141        parent::chdir($dir);
142        $this->relpwd = preg_replace('/^' . preg_quote($this->root, '/') . '\/?/', '', $this->pwd);
143    }
144
145    /**
146    Adds a new file handler for a given media type and event.
147
148    Available events are:
149    - create: file creation
150    - update: file update
151    - remove: file deletion
152
153    @param    type        <b>string</b>        Media type
154    @param    event    <b>string</b>        Event
155    @param    function    <b>callback</b>
156     */
157    public function addFileHandler($type, $event, $function)
158    {
159        if (is_callable($function)) {
160            $this->file_handler[$type][$event][] = $function;
161        }
162    }
163
164    protected function callFileHandler($type, $event)
165    {
166        if (!empty($this->file_handler[$type][$event])) {
167            $args = func_get_args();
168            array_shift($args);
169            array_shift($args);
170
171            foreach ($this->file_handler[$type][$event] as $f) {
172                call_user_func_array($f, $args);
173            }
174        }
175    }
176
177    /**
178    Returns HTML breadCrumb for media manager navigation.
179
180    @param    href        <b>string</b>        URL pattern
181    @param    last        <b>string</b>        Last item pattern
182    @return    <b>string</b> HTML code
183     */
184    public function breadCrumb($href, $last = '')
185    {
186        $res = '';
187        if ($this->relpwd && $this->relpwd != '.') {
188            $pwd   = '';
189            $arr   = explode('/', $this->relpwd);
190            $count = count($arr);
191            foreach ($arr as $v) {
192                if (($last != '') && (0 === --$count)) {
193                    $res .= sprintf($last, $v);
194                } else {
195                    $pwd .= rawurlencode($v) . '/';
196                    $res .= '<a href="' . sprintf($href, $pwd) . '">' . $v . '</a> / ';
197                }
198            }
199        }
200        return $res;
201
202    }
203
204    protected function fileRecord($rs)
205    {
206        if ($rs->isEmpty()) {return;}
207
208        if (!$this->isFileExclude($this->root . '/' . $rs->media_file) && is_file($this->root . '/' . $rs->media_file)) {
209            $f = new fileItem($this->root . '/' . $rs->media_file, $this->root, $this->root_url);
210
211            if ($this->type && $f->type_prefix != $this->type) {
212                return;
213            }
214
215            $meta = @simplexml_load_string($rs->media_meta);
216
217            $f->editable    = true;
218            $f->media_id    = $rs->media_id;
219            $f->media_title = $rs->media_title;
220            $f->media_meta  = $meta instanceof SimpleXMLElement ? $meta : simplexml_load_string('<meta></meta>');
221            $f->media_user  = $rs->user_id;
222            $f->media_priv  = (boolean) $rs->media_private;
223            $f->media_dt    = strtotime($rs->media_dt);
224            $f->media_dtstr = dt::str('%Y-%m-%d %H:%M', $f->media_dt);
225
226            $f->media_image = false;
227
228            if (!$this->core->auth->check('media_admin', $this->core->blog->id)
229                && $this->core->auth->userID() != $f->media_user) {
230                $f->del      = false;
231                $f->editable = false;
232            }
233
234            $type_prefix = explode('/', $f->type);
235            $type_prefix = $type_prefix[0];
236
237            switch ($type_prefix) {
238                case 'image':
239                    $f->media_image = true;
240                    $f->media_icon  = 'image';
241                    break;
242                case 'audio':
243                    $f->media_icon = 'audio';
244                    break;
245                case 'text':
246                    $f->media_icon = 'text';
247                    break;
248                case 'video':
249                    $f->media_icon = 'video';
250                    break;
251                default:
252                    $f->media_icon = 'blank';
253            }
254            switch ($f->type) {
255                case 'application/msword':
256                case 'application/vnd.oasis.opendocument.text':
257                case 'application/vnd.sun.xml.writer':
258                case 'application/pdf':
259                case 'application/postscript':
260                    $f->media_icon = 'document';
261                    break;
262                case 'application/msexcel':
263                case 'application/vnd.oasis.opendocument.spreadsheet':
264                case 'application/vnd.sun.xml.calc':
265                    $f->media_icon = 'spreadsheet';
266                    break;
267                case 'application/mspowerpoint':
268                case 'application/vnd.oasis.opendocument.presentation':
269                case 'application/vnd.sun.xml.impress':
270                    $f->media_icon = 'presentation';
271                    break;
272                case 'application/x-debian-package':
273                case 'application/x-bzip':
274                case 'application/x-gzip':
275                case 'application/x-java-archive':
276                case 'application/rar':
277                case 'application/x-redhat-package-manager':
278                case 'application/x-tar':
279                case 'application/x-gtar':
280                case 'application/zip':
281                    $f->media_icon = 'package';
282                    break;
283                case 'application/octet-stream':
284                    $f->media_icon = 'executable';
285                    break;
286                case 'application/x-shockwave-flash':
287                    $f->media_icon = 'video';
288                    break;
289                case 'application/ogg':
290                    $f->media_icon = 'audio';
291                    break;
292                case 'text/html':
293                    $f->media_icon = 'html';
294                    break;
295            }
296
297            $f->media_type = $f->media_icon;
298            $f->media_icon = sprintf($this->icon_img, $f->media_icon);
299
300            # Thumbnails
301            $f->media_thumb = array();
302            $p              = path::info($f->relname);
303
304            $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG');
305
306            $thumb     = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), $this->root . '/' . $p['dirname'], $p['base'], '%s');
307            $thumb_url = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), $this->root_url . $p['dirname'], $p['base'], '%s');
308
309            # Cleaner URLs
310            $thumb_url = preg_replace('#\./#', '/', $thumb_url);
311            $thumb_url = preg_replace('#(?<!:)/+#', '/', $thumb_url);
312
313            if ($alpha) {
314                $thumb_alt     = sprintf($this->thumb_tp, $this->root . '/' . $p['dirname'], $p['base'], '%s');
315                $thumb_url_alt = sprintf($this->thumb_tp, $this->root_url . $p['dirname'], $p['base'], '%s');
316                # Cleaner URLs
317                $thumb_url_alt = preg_replace('#\./#', '/', $thumb_url_alt);
318                $thumb_url_alt = preg_replace('#(?<!:)/+#', '/', $thumb_url_alt);
319            }
320
321            foreach ($this->thumb_sizes as $suffix => $s) {
322                if (file_exists(sprintf($thumb, $suffix))) {
323                    $f->media_thumb[$suffix] = sprintf($thumb_url, $suffix);
324                } elseif ($alpha && file_exists(sprintf($thumb_alt, $suffix))) {
325                    $f->media_thumb[$suffix] = sprintf($thumb_url_alt, $suffix);
326                }
327            }
328
329            if (isset($f->media_thumb['sq']) && $f->media_type == 'image') {
330                $f->media_icon = $f->media_thumb['sq'];
331            }
332
333            return $f;
334        }
335
336        return;
337    }
338
339    public function setFileSort($type = 'name')
340    {
341        if (in_array($type, array('name-asc', 'name-desc', 'date-asc', 'date-desc'))) {
342            $this->file_sort = $type;
343        }
344    }
345
346    protected function sortFileHandler($a, $b)
347    {
348        if (is_null($a) || is_null($b)) {
349            return (is_null($a) ? 1 : -1);
350        }
351        switch ($this->file_sort) {
352            case 'date-asc':
353                if ($a->media_dt == $b->media_dt) {
354                    return 0;
355                }
356                return ($a->media_dt < $b->media_dt) ? -1 : 1;
357            case 'date-desc':
358                if ($a->media_dt == $b->media_dt) {
359                    return 0;
360                }
361                return ($a->media_dt > $b->media_dt) ? -1 : 1;
362            case 'name-desc':
363                return strcasecmp($b->basename, $a->basename);
364            case 'name-asc':
365            default:
366                return strcasecmp($a->basename, $b->basename);
367        }
368    }
369
370    /**
371    Gets current working directory content (using filesystem)
372
373     */
374    public function getFSDir()
375    {
376        parent::getDir();
377    }
378
379    /**
380    Gets current working directory content.
381
382    @param    type        <b>string</b>        Media type filter
383     */
384    public function getDir($type = null)
385    {
386        if ($type) {
387            $this->type = $type;
388        }
389
390        $media_dir = $this->relpwd ?: '.';
391
392        $strReq =
393        'SELECT media_file, media_id, media_path, media_title, media_meta, media_dt, ' .
394        'media_creadt, media_upddt, media_private, user_id ' .
395        'FROM ' . $this->table . ' ' .
396        "WHERE media_path = '" . $this->path . "' " .
397        "AND media_dir = '" . $this->con->escape($media_dir) . "' ";
398
399        if (!$this->core->auth->check('media_admin', $this->core->blog->id)) {
400            $strReq .= 'AND (media_private <> 1 ';
401
402            if ($this->core->auth->userID()) {
403                $strReq .= "OR user_id = '" . $this->con->escape($this->core->auth->userID()) . "'";
404            }
405            $strReq .= ') ';
406        }
407
408        $rs = $this->con->select($strReq);
409
410        parent::getDir();
411
412        $f_res = array();
413        $p_dir = $this->dir;
414
415        # If type is set, remove items from p_dir
416        if ($this->type) {
417            foreach ($p_dir['files'] as $k => $f) {
418                if ($f->type_prefix != $this->type) {
419                    unset($p_dir['files'][$k]);
420                }
421            }
422        }
423
424        $f_reg = array();
425
426        while ($rs->fetch()) {
427            # File in subdirectory, forget about it!
428            if (dirname($rs->media_file) != '.' && dirname($rs->media_file) != $this->relpwd) {
429                continue;
430            }
431
432            if ($this->inFiles($rs->media_file)) {
433                $f = $this->fileRecord($rs);
434                if ($f !== null) {
435                    if (isset($f_reg[$rs->media_file])) {
436                        # That media is duplicated in the database,
437                        # time to do a bit of house cleaning.
438                        $this->con->execute(
439                            'DELETE FROM ' . $this->table . ' ' .
440                            "WHERE media_id = " . $this->fileRecord($rs)->media_id
441                        );
442                    } else {
443                        $f_res[]                = $this->fileRecord($rs);
444                        $f_reg[$rs->media_file] = 1;
445                    }
446                }
447            } elseif (!empty($p_dir['files']) && $this->relpwd == '') {
448                # Physical file does not exist remove it from DB
449                # Because we don't want to erase everything on
450                # dotclear upgrade, do it only if there are files
451                # in directory and directory is root
452                $this->con->execute(
453                    'DELETE FROM ' . $this->table . ' ' .
454                    "WHERE media_path = '" . $this->con->escape($this->path) . "' " .
455                    "AND media_file = '" . $this->con->escape($rs->media_file) . "' "
456                );
457                $this->callFileHandler(files::getMimeType($rs->media_file), 'remove', $this->pwd . '/' . $rs->media_file);
458            }
459        }
460
461        $this->dir['files'] = $f_res;
462        foreach ($this->dir['dirs'] as $k => $v) {
463            $v->media_icon = sprintf($this->icon_img, ($v->parent ? 'folder-up' : 'folder'));
464        }
465
466        # Check files that don't exist in database and create them
467        if ($this->core->auth->check('media,media_admin', $this->core->blog->id)) {
468            foreach ($p_dir['files'] as $f) {
469                if (!isset($f_reg[$f->relname])) {
470                    if (($id = $this->createFile($f->basename, null, false, null, false)) !== false) {
471                        $this->dir['files'][] = $this->getFile($id);
472                    }
473                }
474            }
475        }
476        try {
477            usort($this->dir['files'], array($this, 'sortFileHandler'));
478        } catch (Exception $e) {}
479    }
480
481    /**
482    Gets file by its id. Returns a filteItem object.
483
484    @param    id        <b>integer</b>        File ID
485    @return    <b>fileItem</b>
486     */
487    public function getFile($id)
488    {
489        $strReq =
490        'SELECT media_id, media_path, media_title, ' .
491        'media_file, media_meta, media_dt, media_creadt, ' .
492        'media_upddt, media_private, user_id ' .
493        'FROM ' . $this->table . ' ' .
494        "WHERE media_path = '" . $this->path . "' " .
495        'AND media_id = ' . (integer) $id . ' ';
496
497        if (!$this->core->auth->check('media_admin', $this->core->blog->id)) {
498            $strReq .= 'AND (media_private <> 1 ';
499
500            if ($this->core->auth->userID()) {
501                $strReq .= "OR user_id = '" . $this->con->escape($this->core->auth->userID()) . "'";
502            }
503            $strReq .= ') ';
504        }
505
506        $rs = $this->con->select($strReq);
507        return $this->fileRecord($rs);
508    }
509
510    /**
511    Search into media db (only).
512
513    @param    query        <b>string</b>        Search query
514    @return boolean     true or false if nothing found
515     */
516    public function searchMedia($query)
517    {
518        if ($query == '') {
519            return false;
520        }
521
522        $strReq =
523        'SELECT media_file, media_id, media_path, media_title, media_meta, media_dt, ' .
524        'media_creadt, media_upddt, media_private, user_id ' .
525        'FROM ' . $this->table . ' ' .
526        "WHERE media_path = '" . $this->path . "' " .
527        "AND (media_title LIKE '%" . $this->con->escape($query) . "%' " .
528        "   OR media_file LIKE '%" . $this->con->escape($query) . "%' " .
529        "   OR media_meta LIKE '<Description>%" . $this->con->escape($query) . "%</Description>')";
530
531        if (!$this->core->auth->check('media_admin', $this->core->blog->id)) {
532            $strReq .= 'AND (media_private <> 1 ';
533
534            if ($this->core->auth->userID()) {
535                $strReq .= "OR user_id = '" . $this->con->escape($this->core->auth->userID()) . "'";
536            }
537            $strReq .= ') ';
538        }
539
540        $rs = $this->con->select($strReq);
541
542        $this->dir = array('dirs' => array(), 'files' => array());
543        $f_res     = array();
544        while ($rs->fetch()) {
545            $fr = $this->fileRecord($rs);
546            if ($fr) {
547                $f_res[] = $fr;
548            }
549        }
550        $this->dir['files'] = $f_res;
551
552        try {
553            usort($this->dir['files'], array($this, 'sortFileHandler'));
554        } catch (Exception $e) {}
555
556        return (count($f_res) > 0 ? true : false);
557    }
558
559    /**
560    Returns media items attached to a blog post. Result is an array containing
561    fileItems objects.
562
563    @param    post_id        <b>integer</b>        Post ID
564    @param    media_id    <b>integer</b>        Optionnal media ID
565    @param    link_type    <b>string</b>        Optionnal link type
566    @return    <b>array</b> Array of fileItems
567     */
568    public function getPostMedia($post_id, $media_id = null, $link_type = null)
569    {
570        $params = array(
571            'post_id'    => $post_id,
572            'media_path' => $this->path
573        );
574        if ($media_id) {
575            $params['media_id'] = (integer) $media_id;
576        }
577        if ($link_type) {
578            $params['link_type'] = $link_type;
579        }
580        $rs = $this->postmedia->getPostMedia($params);
581
582        $res = array();
583
584        while ($rs->fetch()) {
585            $f = $this->fileRecord($rs);
586            if ($f !== null) {
587                $res[] = $f;
588            }
589        }
590
591        return $res;
592    }
593
594    /**
595    @deprecated since version 2.4
596    @see dcPostMedia::addPostMedia
597     */
598    public function addPostMedia($post_id, $media_id, $link_type = 'attachment')
599    {
600        $this->postmedia->addPostMedia($post_id, $media_id, $link_type);
601    }
602
603    /**
604    @deprecated since version 2.4
605    @see dcPostMedia::removePostMedia
606     */
607    public function removePostMedia($post_id, $media_id, $link_type = 'attachment')
608    {
609        $this->postmedia->removePostMedia($post_id, $media_id, $link_type);
610    }
611
612    /**
613    Rebuilds database items collection. Optional <var>$pwd</var> parameter is
614    the path where to start rebuild.
615
616    @param    pwd        <b>string</b>        Directory to rebuild
617     */
618    public function rebuild($pwd = '')
619    {
620        if (!$this->core->auth->isSuperAdmin()) {
621            throw new Exception(__('You are not a super administrator.'));
622        }
623
624        $this->chdir($pwd);
625        parent::getDir();
626
627        $dir = $this->dir;
628
629        foreach ($dir['dirs'] as $d) {
630            if (!$d->parent) {
631                $this->rebuild($d->relname, false);
632            }
633        }
634
635        foreach ($dir['files'] as $f) {
636            $this->chdir(dirname($f->relname));
637            $this->createFile($f->basename);
638        }
639
640        $this->rebuildDB($pwd);
641    }
642
643    protected function rebuildDB($pwd)
644    {
645        $media_dir = $pwd ?: '.';
646
647        $strReq =
648        'SELECT media_file, media_id ' .
649        'FROM ' . $this->table . ' ' .
650        "WHERE media_path = '" . $this->path . "' " .
651        "AND media_dir = '" . $this->con->escape($media_dir) . "' ";
652
653        $rs = $this->con->select($strReq);
654
655        $delReq = 'DELETE FROM ' . $this->table . ' ' .
656            'WHERE media_id IN (%s) ';
657        $del_ids = array();
658
659        while ($rs->fetch()) {
660            if (!is_file($this->root . '/' . $rs->media_file)) {
661                $del_ids[] = (integer) $rs->media_id;
662            }
663        }
664
665        if (!empty($del_ids)) {
666            $this->con->execute(sprintf($delReq, implode(',', $del_ids)));
667        }
668    }
669
670    public function makeDir($d)
671    {
672        $d = files::tidyFileName($d);
673        parent::makeDir($d);
674    }
675
676    /**
677    Creates or updates a file in database. Returns new media ID or false if
678    file does not exist.
679
680    @param    name        <b>string</b>        File name (relative to working directory)
681    @param    title    <b>string</b>        File title
682    @param    private    <b>boolean</b>        File is private
683    @param    dt        <b>string</b>        File date
684    @return    <b>integer</b> New media ID
685     */
686    public function createFile($name, $title = null, $private = false, $dt = null, $force = true)
687    {
688        if (!$this->core->auth->check('media,media_admin', $this->core->blog->id)) {
689            throw new Exception(__('Permission denied.'));
690        }
691
692        $file = $this->pwd . '/' . $name;
693        if (!file_exists($file)) {
694            return false;
695        }
696
697        $media_file = $this->relpwd ? path::clean($this->relpwd . '/' . $name) : path::clean($name);
698        $media_type = files::getMimeType($name);
699
700        $cur = $this->con->openCursor($this->table);
701
702        $strReq = 'SELECT media_id ' .
703        'FROM ' . $this->table . ' ' .
704        "WHERE media_path = '" . $this->con->escape($this->path) . "' " .
705        "AND media_file = '" . $this->con->escape($media_file) . "' ";
706
707        $rs = $this->con->select($strReq);
708
709        if ($rs->isEmpty()) {
710            $this->con->writeLock($this->table);
711            try
712            {
713                $rs       = $this->con->select('SELECT MAX(media_id) FROM ' . $this->table);
714                $media_id = (integer) $rs->f(0) + 1;
715
716                $cur->media_id     = $media_id;
717                $cur->user_id      = (string) $this->core->auth->userID();
718                $cur->media_path   = (string) $this->path;
719                $cur->media_file   = (string) $media_file;
720                $cur->media_dir    = (string) dirname($media_file);
721                $cur->media_creadt = date('Y-m-d H:i:s');
722                $cur->media_upddt  = date('Y-m-d H:i:s');
723
724                $cur->media_title   = !$title ? (string) $name : (string) $title;
725                $cur->media_private = (integer) (boolean) $private;
726
727                if ($dt) {
728                    $cur->media_dt = (string) $dt;
729                } else {
730                    $cur->media_dt = strftime('%Y-%m-%d %H:%M:%S', filemtime($file));
731                }
732
733                try {
734                    $cur->insert();
735                } catch (Exception $e) {
736                    @unlink($name);
737                    throw $e;
738                }
739                $this->con->unlock();
740            } catch (Exception $e) {
741                $this->con->unlock();
742                throw $e;
743            }
744        } else {
745            $media_id = (integer) $rs->media_id;
746
747            $cur->media_upddt = date('Y-m-d H:i:s');
748
749            $cur->update('WHERE media_id = ' . $media_id);
750        }
751
752        $this->callFileHandler($media_type, 'create', $cur, $name, $media_id, $force);
753
754        return $media_id;
755    }
756
757    /**
758    Updates a file in database.
759
760    @param    file        <b>fileItem</b>    Current fileItem object
761    @param    newFile    <b>fileItem</b>    New fileItem object
762     */
763    public function updateFile($file, $newFile)
764    {
765        if (!$this->core->auth->check('media,media_admin', $this->core->blog->id)) {
766            throw new Exception(__('Permission denied.'));
767        }
768
769        $id = (integer) $file->media_id;
770
771        if (!$id) {
772            throw new Exception('No file ID');
773        }
774
775        if (!$this->core->auth->check('media_admin', $this->core->blog->id)
776            && $this->core->auth->userID() != $file->media_user) {
777            throw new Exception(__('You are not the file owner.'));
778        }
779
780        $cur = $this->con->openCursor($this->table);
781
782        # We need to tidy newFile basename. If dir isn't empty, concat to basename
783        $newFile->relname = files::tidyFileName($newFile->basename);
784        if ($newFile->dir) {
785            $newFile->relname = $newFile->dir . '/' . $newFile->relname;
786        }
787
788        if ($file->relname != $newFile->relname) {
789            $newFile->file = $this->root . '/' . $newFile->relname;
790
791            if ($this->isFileExclude($newFile->relname)) {
792                throw new Exception(__('This file is not allowed.'));
793            }
794
795            if (file_exists($newFile->file)) {
796                throw new Exception(__('New file already exists.'));
797            }
798
799            $this->moveFile($file->relname, $newFile->relname);
800
801            $cur->media_file = (string) $newFile->relname;
802            $cur->media_dir  = (string) dirname($newFile->relname);
803        }
804
805        $cur->media_title   = (string) $newFile->media_title;
806        $cur->media_dt      = (string) $newFile->media_dtstr;
807        $cur->media_upddt   = date('Y-m-d H:i:s');
808        $cur->media_private = (integer) $newFile->media_priv;
809
810        $cur->update('WHERE media_id = ' . $id);
811
812        $this->callFileHandler($file->type, 'update', $file, $newFile);
813    }
814
815    /**
816    Uploads a file.
817
818    @param    tmp        <b>string</b>        Full path of temporary uploaded file
819    @param    name        <b>string</b>        File name (relative to working directory)
820    @param    title    <b>string</b>        File title
821    @param    private    <b>boolean</b>        File is private
822     */
823    public function uploadFile($tmp, $name, $title = null, $private = false, $overwrite = false)
824    {
825        if (!$this->core->auth->check('media,media_admin', $this->core->blog->id)) {
826            throw new Exception(__('Permission denied.'));
827        }
828
829        $name = files::tidyFileName($name);
830
831        parent::uploadFile($tmp, $name, $overwrite);
832
833        return $this->createFile($name, $title, $private);
834    }
835
836    /**
837    Creates a file from binary content.
838
839    @param    name        <b>string</b>        File name (relative to working directory)
840    @param    bits        <b>string</b>        Binary file content
841     */
842    public function uploadBits($name, $bits)
843    {
844        if (!$this->core->auth->check('media,media_admin', $this->core->blog->id)) {
845            throw new Exception(__('Permission denied.'));
846        }
847
848        $name = files::tidyFileName($name);
849
850        parent::uploadBits($name, $bits);
851
852        return $this->createFile($name, null, null);
853    }
854
855    /**
856    Removes a file.
857
858    @param    f        <b>fileItem</b>    fileItem object
859     */
860    public function removeFile($f)
861    {
862        if (!$this->core->auth->check('media,media_admin', $this->core->blog->id)) {
863            throw new Exception(__('Permission denied.'));
864        }
865
866        $media_file = $this->relpwd ? path::clean($this->relpwd . '/' . $f) : path::clean($f);
867
868        $strReq = 'DELETE FROM ' . $this->table . ' ' .
869        "WHERE media_path = '" . $this->con->escape($this->path) . "' " .
870        "AND media_file = '" . $this->con->escape($media_file) . "' ";
871
872        if (!$this->core->auth->check('media_admin', $this->core->blog->id)) {
873            $strReq .= "AND user_id = '" . $this->con->escape($this->core->auth->userID()) . "'";
874        }
875
876        $this->con->execute($strReq);
877
878        if ($this->con->changes() == 0) {
879            throw new Exception(__('File does not exist in the database.'));
880        }
881
882        parent::removeFile($f);
883
884        $this->callFileHandler(files::getMimeType($media_file), 'remove', $f);
885    }
886
887    /**
888     * Root directories
889     *
890     * Returns an array of directory under {@link $root} directory.
891     *
892     * @uses fileItem
893     * @return array
894     */
895    public function getDBDirs()
896    {
897        $media_dir = $this->relpwd ?: '.';
898
899        $strReq =
900        'SELECT distinct media_dir ' .
901        'FROM ' . $this->table . ' ' .
902        "WHERE media_path = '" . $this->path . "'";
903        $rs = $this->con->select($strReq);
904        while ($rs->fetch()) {
905            if (is_dir($this->root . '/' . $rs->media_dir)) {
906                $dir[] = ($rs->media_dir == '.' ? '' : $rs->media_dir);
907            }
908
909        }
910
911        return $dir;
912    }
913
914    /**
915    Extract zip file in current location
916
917    @param    f        <b>fileRecord</b>    fileRecord object
918     */
919    public function inflateZipFile($f, $create_dir = true)
920    {
921        $zip = new fileUnzip($f->file);
922        $zip->setExcludePattern($this->exclude_pattern);
923        $list = $zip->getList(false, '#(^|/)(__MACOSX|\.svn|\.DS_Store|\.directory|Thumbs\.db)(/|$)#');
924
925        if ($create_dir) {
926            $zip_root_dir = $zip->getRootDir();
927            if ($zip_root_dir != false) {
928                $destination = $zip_root_dir;
929                $target      = $f->dir;
930            } else {
931                $destination = preg_replace('/\.([^.]+)$/', '', $f->basename);
932                $target      = $f->dir . '/' . $destination;
933            }
934
935            if (is_dir($f->dir . '/' . $destination)) {
936                throw new Exception(sprintf(__('Extract destination directory %s already exists.'), dirname($f->relname) . '/' . $destination));
937            }
938        } else {
939            $target      = $f->dir;
940            $destination = '';
941        }
942
943        $zip->unzipAll($target);
944        $zip->close();
945
946        // Clean-up all extracted filenames
947        $clean = function ($name) {
948            $n = text::deaccent($name);
949            $n = preg_replace('/^[.]/u', '', $n);
950            return preg_replace('/[^A-Za-z0-9._\-\/]/u', '_', $n);
951        };
952        foreach ($list as $zk => $zv) {
953            // Check if extracted file exists
954            $zf = $target . '/' . $zk;
955            if (!$zv['is_dir'] && file_exists($zf)) {
956                $zt = $clean($zf);
957                if ($zt != $zf) {
958                    rename($zf, $zt);
959                }
960            }
961        }
962
963        return dirname($f->relname) . '/' . $destination;
964    }
965
966    /**
967    Returns zip file content
968
969    @param    f        <b>fileRecord</b>    fileRecord object
970    @return <b>array</b>
971     */
972    public function getZipContent($f)
973    {
974        $zip  = new fileUnzip($f->file);
975        $list = $zip->getList(false, '#(^|/)(__MACOSX|\.svn|\.DS_Store|\.directory|Thumbs\.db)(/|$)#');
976        $zip->close();
977        return $list;
978    }
979
980    /**
981    Calls file handlers registered for recreate event
982
983    @param    f    <b>fileItem</b>    fileItem object
984     */
985    public function mediaFireRecreateEvent($f)
986    {
987        $media_type = files::getMimeType($f->basename);
988        $this->callFileHandler($media_type, 'recreate', null, $f->basename); // Args list to be completed as necessary (Franck)
989    }
990
991    /* Image handlers
992    ------------------------------------------------------- */
993    public function imageThumbCreate($cur, $f, $force = true)
994    {
995        $file = $this->pwd . '/' . $f;
996
997        if (!file_exists($file)) {
998            return false;
999        }
1000
1001        $p     = path::info($file);
1002        $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG');
1003        $thumb = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), $p['dirname'], $p['base'], '%s');
1004
1005        try
1006        {
1007            $img = new imageTools();
1008            $img->loadImage($file);
1009
1010            $w = $img->getW();
1011            $h = $img->getH();
1012
1013            if ($force) {
1014                $this->imageThumbRemove($f);
1015            }
1016
1017            foreach ($this->thumb_sizes as $suffix => $s) {
1018                $thumb_file = sprintf($thumb, $suffix);
1019                if (!file_exists($thumb_file) && $s[0] > 0 &&
1020                    ($suffix == 'sq' || $w > $s[0] || $h > $s[0])) {
1021                    $rate = ($s[0] < 100 ? 95 : ($s[0] < 600 ? 90 : 85));
1022                    $img->resize($s[0], $s[0], $s[1]);
1023                    $img->output(($alpha ? 'png' : 'jpeg'), $thumb_file, $rate);
1024                    $img->loadImage($file);
1025                }
1026            }
1027            $img->close();
1028        } catch (Exception $e) {
1029            if ($cur === null) {
1030                # Called only if cursor is null (public call)
1031                throw $e;
1032            }
1033        }
1034    }
1035
1036    protected function imageThumbUpdate($file, $newFile)
1037    {
1038        if ($file->relname != $newFile->relname) {
1039            $p         = path::info($file->relname);
1040            $alpha     = ($p['extension'] == 'png') || ($p['extension'] == 'PNG');
1041            $thumb_old = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), $p['dirname'], $p['base'], '%s');
1042
1043            $p         = path::info($newFile->relname);
1044            $alpha     = ($p['extension'] == 'png') || ($p['extension'] == 'PNG');
1045            $thumb_new = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), $p['dirname'], $p['base'], '%s');
1046
1047            foreach ($this->thumb_sizes as $suffix => $s) {
1048                try {
1049                    parent::moveFile(sprintf($thumb_old, $suffix), sprintf($thumb_new, $suffix));
1050                } catch (Exception $e) {}
1051            }
1052        }
1053    }
1054
1055    public function imageThumbRemove($f)
1056    {
1057        $p     = path::info($f);
1058        $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG');
1059        $thumb = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), '', $p['base'], '%s');
1060
1061        foreach ($this->thumb_sizes as $suffix => $s) {
1062            try {
1063                parent::removeFile(sprintf($thumb, $suffix));
1064            } catch (Exception $e) {}
1065        }
1066    }
1067
1068    protected function imageMetaCreate($cur, $f, $id)
1069    {
1070        $file = $this->pwd . '/' . $f;
1071
1072        if (!file_exists($file)) {
1073            return false;
1074        }
1075
1076        $xml  = new xmlTag('meta');
1077        $meta = imageMeta::readMeta($file);
1078        $xml->insertNode($meta);
1079
1080        $c             = $this->core->con->openCursor($this->table);
1081        $c->media_meta = $xml->toXML();
1082
1083        if ($cur->media_title !== null && $cur->media_title == basename($cur->media_file)) {
1084            if ($meta['Title']) {
1085                $c->media_title = $meta['Title'];
1086            }
1087        }
1088
1089        if ($meta['DateTimeOriginal'] && $cur->media_dt === '') {
1090            # We set picture time to user timezone
1091            $media_ts = strtotime($meta['DateTimeOriginal']);
1092            if ($media_ts !== false) {
1093                $o           = dt::getTimeOffset($this->core->auth->getInfo('user_tz'), $media_ts);
1094                $c->media_dt = dt::str('%Y-%m-%d %H:%M:%S', $media_ts + $o);
1095            }
1096        }
1097
1098        $c->update('WHERE media_id = ' . $id);
1099    }
1100
1101    /**
1102    Returns HTML code for audio player (HTML5 and if possible fallback Flash player)
1103
1104    @param  type        <b>string</b>         audio mime type
1105    @param    url            <b>string</b>        audio URL to play
1106    @param    player        <b>string</b>        Player URL (flash player fallback)
1107    @param    args        <b>array</b>        Player parameters (flash player fallback)
1108    @param  fallback     <b>boolean</b>        Include Flash player fallback
1109    @param     preload        <b>boolean</b>        Add preload="auto" attribute if true, else preload="none"
1110    @return    <b>string</b>
1111     */
1112    public static function audioPlayer($type, $url, $player = null, $args = null, $fallback = true, $preload = true)
1113    {
1114        $audio =
1115            '<audio controls preload="' . ($preload ? 'auto' : 'none') . '">' .
1116            '<source src="' . $url . '">';
1117
1118        if ($fallback && $type == 'audio/mpeg3') {
1119            // Include Flash player fallback
1120            if (!$player) {
1121                $player = 'player_mp3.swf';
1122            }
1123
1124            if (!is_array($args)) {
1125                $args = array(
1126                    'showvolume'      => 1,
1127                    'loadingcolor'    => 'ff9900',
1128                    'bgcolor1'        => 'eeeeee',
1129                    'bgcolor2'        => 'cccccc',
1130                    'buttoncolor'     => '0066cc',
1131                    'buttonovercolor' => 'ff9900',
1132                    'slidercolor1'    => 'cccccc',
1133                    'slidercolor2'    => '999999',
1134                    'sliderovercolor' => '0066cc'
1135                );
1136            }
1137
1138            $args['mp3'] = $url;
1139
1140            if (empty($args['width'])) {
1141                $args['width'] = 200;
1142            }
1143            if (empty($args['height'])) {
1144                $args['height'] = 20;
1145            }
1146
1147            $vars = array();
1148            foreach ($args as $k => $v) {
1149                $vars[] = $k . '=' . $v;
1150            }
1151
1152            $audio .=
1153            '<object type="application/x-shockwave-flash" ' .
1154            'data="' . $player . '" ' .
1155            'width="' . $args['width'] . '" height="' . $args['height'] . '">' .
1156            '<param name="movie" value="' . $player . '" />' .
1157            '<param name="wmode" value="transparent" />' .
1158            '<param name="FlashVars" value="' . implode('&amp;', $vars) . '" />' .
1159            __('Embedded Audio Player') .
1160                '</object>';
1161        }
1162
1163        $audio .=
1164            '</audio>';
1165
1166        return $audio;
1167    }
1168
1169    /**
1170    Returns HTML code for video player (HTML5 and if possible fallback Flash player)
1171
1172    @param  type        <b>string</b>         video mime type
1173    @param    url            <b>string</b>        video URL to play
1174    @param    player        <b>string</b>        Player URL (flash player fallback)
1175    @param    args        <b>array</b>        Player parameters (flash player fallback)
1176    @param  fallback     <b>boolean</b>        Include Flash player fallback (if not .flv)
1177    @param     preload        <b>boolean</b>        Add preload="auto" attribute if true, else preload="none"
1178    @return    <b>string</b>
1179     */
1180    public static function videoPlayer($type, $url, $player = null, $args = null, $fallback = true, $preload = true)
1181    {
1182        $video = '';
1183
1184        // Cope with width and height, if given
1185        $width  = 400;
1186        $height = 300;
1187        if (is_array($args)) {
1188            if (!empty($args['width']) && $args['width']) {
1189                $width = (int) $args['width'];
1190            }
1191            if (!empty($args['height']) && $args['height']) {
1192                $height = (int) $args['height'];
1193            }
1194        }
1195
1196        if ($type != 'video/x-flv') {
1197            $video =
1198                '<video controls preload="' . ($preload ? 'auto' : 'none') . '"' .
1199                ($width ? ' width="' . $width . '"' : '') .
1200                ($height ? ' height="' . $height . '"' : '') . '>' .
1201                '<source src="' . $url . '">';
1202        }
1203
1204        if ($type == 'video/x-flv' || ($fallback && ($type == 'video/mp4' || $type == 'video/x-m4v'))) {
1205            // Include Flash player fallback
1206            if (!$player) {
1207                $player = 'player_flv.swf';
1208            }
1209
1210            if (!is_array($args)) {
1211                $args = array(
1212                    'margin'          => 1,
1213                    'showvolume'      => 1,
1214                    'showtime'        => 1,
1215                    'showfullscreen'  => 1,
1216                    'buttonovercolor' => 'ff9900',
1217                    'slidercolor1'    => 'cccccc',
1218                    'slidercolor2'    => '999999',
1219                    'sliderovercolor' => '0066cc'
1220                );
1221            }
1222
1223            $args['flv'] = $url;
1224
1225            if (empty($args['width'])) {
1226                $args['width'] = 400;
1227            }
1228            if (empty($args['height'])) {
1229                $args['height'] = 300;
1230            }
1231
1232            $vars = array();
1233            foreach ($args as $k => $v) {
1234                $vars[] = $k . '=' . $v;
1235            }
1236
1237            $video .=
1238            '<object type="application/x-shockwave-flash" ' .
1239            'data="' . $player . '" ' .
1240            'width="' . $args['width'] . '" height="' . $args['height'] . '">' .
1241            '<param name="movie" value="' . $player . '" />' .
1242            '<param name="wmode" value="transparent" />' .
1243            '<param name="allowFullScreen" value="true" />' .
1244            '<param name="FlashVars" value="' . implode('&amp;', $vars) . '" />' .
1245            __('Embedded Video Player') .
1246                '</object>';
1247        }
1248
1249        if ($type != 'video/x-flv') {
1250            $video .=
1251                '</video>';
1252        }
1253
1254        return $video;
1255    }
1256
1257    /**
1258    Returns HTML code for MP3 player
1259
1260    @param    url            <b>string</b>        MP3 URL to play
1261    @param    player        <b>string</b>        Player URL
1262    @param    args        <b>array</b>        Player parameters
1263    @param  fallback     <b>boolean</b>        Include Flash player fallback
1264    @param     preload        <b>boolean</b>        Add preload="auto" attribute if true, else preload="none"
1265    @return    <b>string</b>
1266     */
1267    public static function mp3player($url, $player = null, $args = null, $fallback = true, $preload = true)
1268    {
1269        if (!$player) {
1270            $player = 'player_mp3.swf';
1271        }
1272
1273        if (!is_array($args)) {
1274            $args = array(
1275                'showvolume'      => 1,
1276                'loadingcolor'    => 'ff9900',
1277                'bgcolor1'        => 'eeeeee',
1278                'bgcolor2'        => 'cccccc',
1279                'buttoncolor'     => '0066cc',
1280                'buttonovercolor' => 'ff9900',
1281                'slidercolor1'    => 'cccccc',
1282                'slidercolor2'    => '999999',
1283                'sliderovercolor' => '0066cc'
1284            );
1285        }
1286
1287        $args['mp3'] = $url;
1288
1289        if (empty($args['width'])) {
1290            $args['width'] = 200;
1291        }
1292        if (empty($args['height'])) {
1293            $args['height'] = 20;
1294        }
1295
1296        $vars = array();
1297        foreach ($args as $k => $v) {
1298            $vars[] = $k . '=' . $v;
1299        }
1300
1301        return
1302            '<audio controls preload="' . ($preload ? 'auto' : 'none') . '">' .
1303            '<source src="' . $url . '" type="audio/mpeg">' .
1304            ($fallback ?
1305            '<object type="application/x-shockwave-flash" ' .
1306            'data="' . $player . '" ' .
1307            'width="' . $args['width'] . '" height="' . $args['height'] . '">' .
1308            '<param name="movie" value="' . $player . '" />' .
1309            '<param name="wmode" value="transparent" />' .
1310            '<param name="FlashVars" value="' . implode('&amp;', $vars) . '" />' .
1311            __('Embedded Audio Player') .
1312            '</object>' : '') .
1313            '</audio>';
1314    }
1315
1316    /**
1317    Returns HTML code for FLV player
1318
1319    @param    url        <b>string</b>        FLV URL to play
1320    @param    player    <b>string</b>        Player URL
1321    @param    args        <b>array</b>        Player parameters
1322    @return    <b>string</b>
1323     */
1324    public static function flvplayer($url, $player = null, $args = null)
1325    {
1326        if (!$player) {
1327            $player = 'player_flv.swf';
1328        }
1329
1330        if (!is_array($args)) {
1331            $args = array(
1332                'margin'          => 1,
1333                'showvolume'      => 1,
1334                'showtime'        => 1,
1335                'showfullscreen'  => 1,
1336                'buttonovercolor' => 'ff9900',
1337                'slidercolor1'    => 'cccccc',
1338                'slidercolor2'    => '999999',
1339                'sliderovercolor' => '0066cc'
1340            );
1341        }
1342
1343        $args['flv'] = $url;
1344
1345        if (empty($args['width'])) {
1346            $args['width'] = 400;
1347        }
1348        if (empty($args['height'])) {
1349            $args['height'] = 300;
1350        }
1351
1352        $vars = array();
1353        foreach ($args as $k => $v) {
1354            $vars[] = $k . '=' . $v;
1355        }
1356
1357        return
1358        '<object type="application/x-shockwave-flash" ' .
1359        'data="' . $player . '" ' .
1360        'width="' . $args['width'] . '" height="' . $args['height'] . '">' .
1361        '<param name="movie" value="' . $player . '" />' .
1362        '<param name="wmode" value="transparent" />' .
1363        '<param name="allowFullScreen" value="true" />' .
1364        '<param name="FlashVars" value="' . implode('&amp;', $vars) . '" />' .
1365        __('Embedded Video Player') .
1366            '</object>';
1367    }
1368}
Note: See TracBrowser for help on using the repository browser.

Sites map