PluginProbe
Extendify / 3.1.5
Extendify v3.1.5
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 0.7.0 All 126 releases
extendify / app / Draft / Controllers / ImageController.php

ImageController.php in Extendify 3.1.5, at app/Draft/Controllers/ImageController.php

154 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Image Controller
5 */
6
7 namespace Extendify\Draft\Controllers;
8
9 defined('ABSPATH') || die('No direct access.');
10
11 // Try to execute set the limit to something that will work for 60s duration.
12 // phpcs:ignore WordPress.PHP.NoSilencedErrors, Generic.PHP.NoSilencedErrors.Discouraged
13 if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
14 // phpcs:ignore WordPress.PHP.NoSilencedErrors, Generic.PHP.NoSilencedErrors.Discouraged
15 @set_time_limit(60);
16 }
17
18 use Extendify\Shared\Services\Sanitizer;
19
20 /**
21 * The controller for uploading images to the Media Library.
22 */
23
24 class ImageController
25 {
26 /**
27 * Upload the provided image
28 *
29 * @param \WP_REST_Request $request - The request.
30 * @return \WP_REST_Response
31 */
32 public static function uploadMedia(\WP_REST_Request $request)
33 {
34 if (! function_exists('\media_sideload_image')) {
35 require_once ABSPATH . 'wp-admin/includes/media.php';
36 require_once ABSPATH . 'wp-admin/includes/file.php';
37 require_once ABSPATH . 'wp-admin/includes/image.php';
38 }
39
40 $imageId = \media_sideload_image($request->get_param('source'), 0, null, 'id');
41
42 // Without this the caller can't tell a failed upload from a declined one.
43 if (\is_wp_error($imageId)) {
44 return new \WP_REST_Response(['message' => $imageId->get_error_message()], 500);
45 }
46
47 if ($request->get_param('ai_generated')) {
48 update_post_meta($imageId, 'extendify_ai_generated', true);
49 $label = $request->get_file_params()['disclosure_label'] ?? null;
50 if (isset($label['tmp_name'])) {
51 self::stampImage($imageId, $label['tmp_name']);
52 }
53 }
54
55 if ($request->get_param('alt_text')) {
56 update_post_meta(
57 $imageId,
58 '_wp_attachment_image_alt',
59 Sanitizer::sanitizeText($request->get_param('alt_text'))
60 );
61 }
62
63 if ($request->get_param('caption')) {
64 wp_update_post(
65 Sanitizer::sanitizeArray([
66 'ID' => $imageId,
67 'post_excerpt' => $request->get_param('caption'),
68 ])
69 );
70 }
71
72 $imageObject = \get_post($imageId);
73 $altText = (get_post_meta($imageId, '_wp_attachment_image_alt', true))
74 ? get_post_meta($imageId, '_wp_attachment_image_alt', true)
75 : '';
76
77 return new \WP_REST_Response(
78 [
79 'id' => $imageId,
80 'caption' => ['raw' => $imageObject->post_excerpt],
81 'source_url' => wp_get_attachment_url($imageId),
82 'alt_text' => $altText,
83 ]
84 );
85 }
86
87 /**
88 * Composite the client-rendered disclosure label onto the attachment,
89 * bottom-right at a 16px inset, matching the canvas-path stamp.
90 *
91 * @param int $imageId - The attachment ID.
92 * @param string $labelPath - Path to the uploaded label PNG.
93 * @return void
94 */
95 private static function stampImage($imageId, $labelPath)
96 {
97 $file = \get_attached_file($imageId);
98 $type = $file ? (\wp_check_filetype($file)['type'] ?? null) : null;
99 $loaders = [
100 'image/jpeg' => 'imagecreatefromjpeg',
101 'image/png' => 'imagecreatefrompng',
102 'image/webp' => 'imagecreatefromwebp',
103 ];
104 if (!isset($loaders[$type]) || !function_exists($loaders[$type]) || !is_file($file)) {
105 return;
106 }
107
108 // phpcs:ignore WordPress.PHP.NoSilencedErrors, Generic.PHP.NoSilencedErrors.Discouraged
109 $image = @call_user_func($loaders[$type], $file);
110 // phpcs:ignore WordPress.PHP.NoSilencedErrors, Generic.PHP.NoSilencedErrors.Discouraged
111 $label = @imagecreatefrompng($labelPath);
112 if (!$image || !$label) {
113 return;
114 }
115
116 $width = imagesx($image);
117 $height = imagesy($image);
118 // The client renders the label at a 48px font; the canvas stamp uses 2% of the shorter side.
119 $scale = max(12, round(min($width, $height) * 0.02)) / 48;
120 $labelWidth = (int) round(imagesx($label) * $scale);
121 $labelHeight = (int) round(imagesy($label) * $scale);
122 imagealphablending($image, true);
123 imagecopyresampled(
124 $image,
125 $label,
126 ($width - $labelWidth - 16),
127 ($height - $labelHeight - 16),
128 0,
129 0,
130 $labelWidth,
131 $labelHeight,
132 imagesx($label),
133 imagesy($label)
134 );
135
136 if ($type === 'image/jpeg') {
137 imagejpeg($image, $file, 90);
138 }
139
140 if ($type === 'image/png') {
141 imagesavealpha($image, true);
142 imagepng($image, $file);
143 }
144
145 if ($type === 'image/webp') {
146 imagewebp($image, $file, 90);
147 }
148
149 // Sub-sizes were generated from the unstamped original; rebuild them.
150 $metadata = \wp_generate_attachment_metadata($imageId, $file);
151 \wp_update_attachment_metadata($imageId, $metadata);
152 }
153 }
154