PluginProbe
Extendify / 3.1.5
Extendify v3.1.5
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / app / Shared / Services / Import / ImageUploader.php

ImageUploader.php in Extendify 3.1.5, at app/Shared/Services/Import/ImageUploader.php

261 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Image uploader class
5 */
6
7 namespace Extendify\Shared\Services\Import;
8
9 defined('ABSPATH') || die('No direct access.');
10
11 /**
12 * This class responsible for uploading the image.
13 */
14
15 class ImageUploader
16 {
17 /**
18 * The mime types we support !!
19 *
20 * @var string[]
21 */
22 protected $mimes = [
23 'image/gif' => '.gif',
24 'image/jpeg' => '.jpg',
25 'image/png' => '.png',
26 'image/x-png' => '.png',
27 'image/jp2' => '.jp2',
28 'image/jpx' => '.jp2',
29 'image/webp' => '.wbmp',
30 'image/avif' => '.avif',
31 ];
32
33 /**
34 * The images domains we use
35 *
36 * @var string[] the domain names.
37 */
38 public static $imagesDomains = [
39 'unsplash.com',
40 'extendify.com',
41 ];
42
43 /**
44 * Check whether the url points at one of our image domains.
45 *
46 * @param string $url The image url to check.
47 * @return bool
48 */
49 public static function isAllowedImageHost($url)
50 {
51 $host = strtolower((string) wp_parse_url($url, PHP_URL_HOST));
52
53 foreach (self::$imagesDomains as $domain) {
54 if ($host === $domain || str_ends_with($host, '.' . $domain)) {
55 return true;
56 }
57 }
58
59 return false;
60 }
61
62 /**
63 * Upload the image and return the attachment information
64 * If the attachment is already there, then return the
65 * attachment information only.
66 *
67 * @param string $image the image url to upload.
68 * @param string|null $author the WordPress post author.
69 * @return array|\WP_Error
70 */
71 public function uploadImage($image, $author = null) // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
72 {
73 require_once ABSPATH . 'wp-admin/includes/image.php';
74
75 $image = preg_replace('/(\?.*?)\?/', '$1&', $image);
76 $image = str_replace('%2C', ',', $image);
77 // If the attachment has been already uploaded, just return it.
78 $attachment = $this->getAttachmentIfExists($image);
79
80 if ($attachment instanceof \WP_Post) {
81 return [
82 'attachment_id' => $attachment->ID,
83 'url' => $attachment->guid,
84 ];
85 }
86
87 $imageHeadersInformation = wp_remote_retrieve_headers(wp_safe_remote_head($image));
88
89 if (!empty($imageHeadersInformation)) {
90 $headers = $imageHeadersInformation->getAll();
91 $fileMimeType = $headers['content-type'];
92 } else {
93 $fileMimeType = wp_get_image_mime($image);
94 }
95
96 if (!array_key_exists($fileMimeType, $this->mimes)) {
97 return new \WP_Error(2002, 'File type is not allowed.');
98 }
99
100 if (!self::isAllowedImageHost($image)) {
101 $imageUrl = esc_url_raw($image);
102 } else {
103 $parsedUrl = wp_parse_url($image);
104 parse_str(($parsedUrl['query'] ?? ''), $params);
105
106 if (!isset($params['w'])) {
107 $params['w'] = 1280;
108 }
109
110 if (isset($params['orientation'])) {
111 if ($params['orientation'] === 'portrait') {
112 $params['h'] = 1440;
113 unset($params['w']);
114 } elseif (in_array($params['orientation'], ['landscape', 'square'], true) && isset($params['w'])) {
115 $params['w'] = 1440;
116 }
117
118 unset($params['orientation']);
119 }
120
121 $params['auto'] = 'auto,compress';
122 $params['q'] = 70;
123
124 $imageUrl = $parsedUrl['scheme'] . '://'
125 . $parsedUrl['host']
126 . $parsedUrl['path']
127 . '?'
128 . http_build_query($params);
129 }//end if
130
131 $imageSha = sha1($image);
132 $upload = $this->handleImageUpload($imageUrl, $imageSha, $fileMimeType);
133 if (is_wp_error($upload)) {
134 return $upload;
135 }
136
137 $attachmentId = $this->createAttachment($upload, $image, $author);
138 if (is_wp_error($attachmentId)) {
139 return $attachmentId;
140 }
141
142 $upload['attachment_id'] = $attachmentId;
143 return $upload;
144 }
145
146 /**
147 * Handle the image upload process.
148 *
149 * @param string $imageUrl The image URL.
150 * @param string $imageSha The image SHA.
151 * @param string $fileMimeType The file mime type.
152 * @return array|\WP_Error
153 */
154 protected function handleImageUpload($imageUrl, $imageSha, $fileMimeType)
155 {
156 $upload = $this->upload($imageUrl, $imageSha, $fileMimeType);
157
158 if ($upload['error']) {
159 return new \WP_Error(2003, $upload['error']);
160 }
161
162 if (!wp_getimagesize($upload['file'])) {
163 // phpcs:ignore WordPress.PHP.NoSilencedErrors, Generic.PHP.NoSilencedErrors.Discouraged
164 @unlink($upload['file']);
165 $imageUrl = str_replace('avif', 'jpg', $imageUrl);
166 $upload = $this->upload($imageUrl, $imageSha, 'image/jpeg');
167 }
168
169 // phpcs:ignore WordPress.PHP.NoSilencedErrors, Generic.PHP.NoSilencedErrors.Discouraged
170 if (!@filesize($upload['file']) || !wp_getimagesize($upload['file'])) {
171 // phpcs:ignore WordPress.PHP.NoSilencedErrors, Generic.PHP.NoSilencedErrors.Discouraged
172 @unlink($upload['file']);
173 return new \WP_Error(2001, 'File is not a valid image.');
174 }
175
176 return $upload;
177 }
178
179 /**
180 * Create the attachment in WordPress.
181 *
182 * @param array $upload The upload information.
183 * @param string $image The original image URL.
184 * @param string|null $author The post author.
185 * @return int|\WP_Error
186 */
187 protected function createAttachment($upload, $image, $author)
188 {
189 $attachment = [
190 'guid' => $upload['url'],
191 'post_mime_type' => $upload['type'],
192 'post_title' => sha1($image),
193 'post_content' => '',
194 'post_status' => 'inherit',
195 'post_author' => $author,
196 ];
197
198 $attachmentId = wp_insert_attachment($attachment, $upload['file']);
199
200 if (is_wp_error($attachmentId) || !$attachmentId) {
201 return new \WP_Error(2004, 'There was an error while adding the attachment record in the database.');
202 }
203
204 $metadata = wp_generate_attachment_metadata($attachmentId, $upload['file']);
205 if (!empty($metadata)) {
206 wp_update_attachment_metadata($attachmentId, $metadata);
207 }
208
209 update_post_meta($attachmentId, '_extendify_source_url', $image);
210
211 return $attachmentId;
212 }
213
214 /**
215 * Upload the image and return the uploaded file information.
216 *
217 * @param string $imageUrl The image url to upload.
218 * @param string $imageSha The image sha.
219 * @param string $fileMimeType The file mime type.
220 * @return array {
221 * Information about the newly-uploaded file.
222 *
223 * @type string $file Filename of the newly-uploaded file.
224 * @type string $url URL of the uploaded file.
225 * @type string $type File type.
226 * @type string|false $error Error message, if there has been an error.
227 * }
228 */
229 protected function upload($imageUrl, $imageSha, $fileMimeType)
230 {
231 $response = wp_safe_remote_get($imageUrl);
232 $body = trim(wp_remote_retrieve_body($response));
233 return wp_upload_bits($imageSha . $this->mimes[$fileMimeType], null, $body);
234 }
235
236 /**
237 * Check if the image has been already uploaded or not, if yes
238 * then return the attachment information.
239 *
240 * @param string $image the image url we need to check for.
241 * @return array|\WP_Post|null
242 */
243 protected function getAttachmentIfExists($image)
244 {
245 $postId = attachment_url_to_postid($image);
246 if ($postId) {
247 return get_post($postId);
248 }
249
250 $attachment = get_posts([
251 'post_type' => 'attachment',
252 'numberposts' => 1,
253 's' => sha1($image),
254 'post_status' => 'inherit',
255 'post_mime_type' => implode(',', array_keys($this->mimes)),
256 ]);
257
258 return $attachment ? $attachment[0] : [];
259 }
260 }
261