PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 All 36 releases
vikbooking / admin / helpers / src / chat / attachment / remote.php

remote.php in VikBooking Hotel Booking Engine & PMS trunk, at admin/helpers/src/chat/attachment/remote.php

181 lines 6.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2026 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * This class holds the information of a chat attachment as remote file.
16 *
17 * @since 1.8.8
18 */
19 class VBOChatAttachmentRemote extends VBOChatAttachment
20 {
21 /**
22 * Class constructor.
23 *
24 * @param string $url The URI of the remote file.
25 * @param string $path The path where the attachment should be downloaded.
26 * @param string $headers Optional headers to download the file.
27 */
28 public function __construct(string $url, string $path, array $headers = [])
29 {
30 // download remote file
31 $file = $this->download($url, $headers);
32
33 // construct through parent
34 parent::__construct([
35 'path' => $path,
36 'name' => $file['name'],
37 ]);
38
39 // save file locally
40 $this->save($file['buffer']);
41 }
42
43 /**
44 * Downloads the file locally.
45 *
46 * @param string $url The URI of the remote file.
47 * @param array $headers The request headers.
48 *
49 * @return array An associative array holding the file details.
50 */
51 protected function download(string $url, array $headers)
52 {
53 // default to same file name used by the URL with no query arguments
54 $filename = explode('?', basename($url))[0];
55
56 if (preg_match("/\.(php|html)$/i", $filename)) {
57 // do not register this kind of files
58 throw new \DomainException('Cannot accept files with this extension', 403);
59 }
60
61 // download remote file content from URL
62 $response = (new JHttp)->get($url, $headers, $timeout = 30);
63
64 if (!in_array($response->code, [200, 201, 202])) {
65 // the request returned an invalid status code, propagate error
66 throw new UnexpectedValueException($response->body ?: 'Error', $response->code ?: 500);
67 }
68
69 // make sure the file name has got a file extension
70 if (!preg_match('/\.[a-z0-9]{3,}$/i', $filename)) {
71 // get content-type from response headers (try both lower-case and Pascal-Case notations)
72 $contentType = $response->headers['content-type'] ?? ($response->headers['Content-Type'] ?? null);
73
74 if (is_array($contentType)) {
75 // in case of multiple headers, fetch only the first available one
76 $contentType = array_shift($contentType);
77 }
78
79 if (!$this->checkMimeType($contentType)) {
80 throw new DomainException('Unsupported [' . $contentType . '] MIME type for the provided file.', 415);
81 }
82
83 // append file extension to file name from detected mime-type
84 $filename .= '.' . $this->getFileExtension($contentType);
85 }
86
87 return [
88 'name' => $filename,
89 'buffer' => (string) $response->body,
90 ];
91 }
92
93 /**
94 * Saves the file locally.
95 *
96 * @param string $buffer
97 *
98 * @return void
99 */
100 protected function save(string $buffer)
101 {
102 if (!JFile::write($this->getPath(), $buffer)) {
103 throw new RuntimeException('Unable to save attachment on disk', 403);
104 }
105 }
106
107 /**
108 * Check here if we are downloading a supported file.
109 *
110 * @param string $type The MIME type to check.
111 *
112 * @return string True if supported, false otherwise.
113 */
114 protected function checkMimeType(string $type)
115 {
116 // additional allowed document mime types
117 $docMimeTypes = [
118 'text/plain',
119 'application/msword',
120 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
121 'application/vnd.ms-excel',
122 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
123 'application/vnd.ms-powerpoint',
124 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
125 'application/x-iwork-pages-sffpages',
126 'application/vnd.apple.pages',
127 'application/x-iwork-numbers-sffnumbers',
128 'application/vnd.apple.numbers',
129 'audio/ogg; codecs=opus',
130 ];
131
132 if (in_array($type, $docMimeTypes)) {
133 return true;
134 }
135
136 /**
137 * Accept images (png, gif, jpg), videos (mp4, quicktime) and documents.
138 */
139 return preg_match("/^image\/(png|jpe?g|gif)|video\/(mp4|quicktime|mov)|audio\/ogg|application\/(pdf|ms-excel|rtf)$/", $type);
140 }
141
142 /**
143 * Returns the supported file extension from the given mime type.
144 *
145 * @param string $type The file mime type.
146 *
147 * @return string The supported file extension.
148 */
149 protected function getFileExtension(string $type)
150 {
151 // special mime types
152 $specialMimeTypes = [
153 'text/plain' => 'txt',
154 'application/msword' => 'doc',
155 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
156 'application/vnd.ms-excel' => 'xls',
157 'application/ms-excel' => 'xls',
158 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx',
159 'application/vnd.ms-powerpoint' => 'ppt',
160 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'pptx',
161 'application/x-iwork-pages-sffpages' => 'pages',
162 'application/vnd.apple.pages' => 'pages',
163 'application/x-iwork-numbers-sffnumbers' => 'numbers',
164 'application/vnd.apple.numbers' => 'numbers',
165 'video/quicktime' => 'mov',
166 ];
167
168 if (isset($specialMimeTypes[$type])) {
169 // supported special extension
170 return $specialMimeTypes[$type];
171 }
172
173 // default to second mime type chunk
174 $type = explode('/', $type)[1];
175 // get rid of secondary header information (e.g. audio/ogg; codecs=opus)
176 $type = explode(';', $type)[0];
177
178 return trim($type);
179 }
180 }
181