xref: /dokuwiki/inc/File/MediaFile.php (revision 8788dbbd585b42284320d64cc932f3c875eab6b2)
1<?php
2
3namespace dokuwiki\File;
4
5use Exception;
6use JpegMeta;
7use splitbrain\slika\ImageInfo;
8
9class MediaFile
10{
11    protected $id;
12    protected $rev;
13    protected $path;
14
15    protected $mime;
16    protected $ext;
17    protected $downloadable;
18
19    protected $width;
20    protected $height;
21    protected $meta;
22
23    /**
24     * MediaFile constructor.
25     * @param string $id
26     * @param string|int $rev optional revision
27     */
28    public function __construct($id, $rev = '')
29    {
30        $this->id = $id; //FIXME should it be cleaned?
31        $this->path = mediaFN($id, $rev);
32        $this->rev = $rev;
33
34        [$this->ext, $this->mime, $this->downloadable] = mimetype($this->path, false);
35    }
36
37    /** @return string */
38    public function getId()
39    {
40        return $this->id;
41    }
42
43    /** @return string|int Empty string for current version */
44    public function getRev()
45    {
46        return $this->rev;
47    }
48
49    /** @return string */
50    public function getPath()
51    {
52        return $this->path;
53    }
54
55    /**
56     * The ID without namespace, used for display purposes
57     *
58     * @return string
59     */
60    public function getDisplayName()
61    {
62        return noNS($this->id);
63    }
64
65    /** @return string */
66    public function getMime()
67    {
68        if (!$this->mime) return 'application/octet-stream';
69        return $this->mime;
70    }
71
72    /** @return string */
73    public function getExtension()
74    {
75        return (string)$this->ext;
76    }
77
78    /**
79     * Similar to the extesion but does some clean up
80     *
81     * @return string
82     */
83    public function getIcoClass()
84    {
85        $ext = $this->getExtension();
86        if ($ext === '') $ext = 'file';
87        return preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
88    }
89
90    /**
91     * Should this file be downloaded instead being displayed inline?
92     *
93     * @return bool
94     */
95    public function isDownloadable()
96    {
97        return $this->downloadable;
98    }
99
100    /** @return int */
101    public function getFileSize()
102    {
103        return filesize($this->path);
104    }
105
106    /** @return int */
107    public function getLastModified()
108    {
109        return filemtime($this->path);
110    }
111
112    /** @return bool */
113    public function isWritable()
114    {
115        return is_writable($this->path);
116    }
117
118    /** @return bool */
119    public function isImage()
120    {
121        return (str_starts_with($this->mime, 'image/'));
122    }
123
124    /**
125     * initializes width and height for images when requested
126     */
127    protected function initSizes()
128    {
129        $this->width = 0;
130        $this->height = 0;
131        if (!$this->isImage()) return;
132        $info = getimagesize($this->path);
133        if ($info === false) return;
134        [$this->width, $this->height] = $info;
135    }
136
137    /**
138     * Returns the width if this is a supported image, 0 otherwise
139     *
140     * @return int
141     */
142    public function getWidth()
143    {
144        if ($this->width === null) $this->initSizes();
145        return $this->width;
146    }
147
148    /**
149     * Returns the height if this is a supported image, 0 otherwise
150     *
151     * @return int
152     */
153    public function getHeight()
154    {
155        if ($this->height === null) $this->initSizes();
156        return $this->height;
157    }
158
159    /**
160     * Returns the final display dimensions a fetch.php URL with the given
161     * parameters would produce, including EXIF auto-rotation
162     *
163     * @param int $w requested width (0 = no constraint)
164     * @param int $h requested height (0 = no constraint)
165     * @param bool $crop true for center-crop, false for bounding-box fit
166     * @return array [width, height]; [0, 0] for non-images/unreadable files
167     */
168    public function getDisplayDimensions($w = 0, $h = 0, $crop = false)
169    {
170        try {
171            $info = (new ImageInfo($this->path))->autorotate();
172        } catch (Exception) {
173            return [0, 0];
174        }
175        if ($w === 0 && $h === 0) return $info->getDimensions();
176        if ($crop) return $info->crop($w, $h)->getDimensions();
177        return $info->resize($w, $h)->getDimensions();
178    }
179
180    /**
181     * Returns the permissions the current user has on the file
182     *
183     * @todo doing this for each file within a namespace is a waste, we need to cache this somehow
184     * @return int
185     */
186    public function userPermission()
187    {
188        return auth_quickaclcheck(getNS($this->id) . ':*');
189    }
190
191    /** @return JpegMeta */
192    public function getMeta()
193    {
194        if ($this->meta === null) $this->meta = new JpegMeta($this->path);
195        return $this->meta;
196    }
197}
198