Dotclear

source: inc/core/class.dc.media.php @ 3874:ab8368569446

Revision 3874:ab8368569446, 46.2 KB checked in by franck <carnet.franck.paul@…>, 7 years ago (diff)

short notation for array (array() → [])

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

Sites map