Dotclear

source: inc/core/class.dc.media.php @ 3731:3770620079d4

Revision 3731:3770620079d4, 46.5 KB checked in by franck <carnet.franck.paul@…>, 8 years ago (diff)

Simplify licence block at the beginning of each file

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

Sites map