Skip to content

Commit c888052

Browse files
authored
release(minor): features
- Optimole is now fully translated into German! This update makes our service more convenient for our German-speaking customers and helps you support your German-speaking clients more effectively. - We now have a PHP SDK available on GitHub: [Optimole PHP SDK](https://github.com/Optimole/optimole-php-sdk). This SDK simplifies the integration of Optimole’s features with any PHP-based website, making the process straightforward and efficient. - You can now associate a billing email to receive invoices. For more details, check out our [documentation](https://docs.optimole.com/article/1992-setting-a-billing-email-for-invoice-delivery). - We've improved Largest Contentful Paint (LCP) by prioritizing the loading of initial images that are not affected by lazy loading. - We've also improved LCP by using the srcset attribute for non-lazyloaded images. - We've fixed various issues with offload compatibility to ensure all images load properly, making the service more robust. - We've resolved an issue where the offloading process was getting stuck on large websites, making the process smoother and more reliable. - We've improved the handling and sanitization of SVG files.
2 parents ae0d38f + 125a3ca commit c888052

39 files changed

+754
-1346
lines changed

assets/src/dashboard/parts/connected/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import Help from './help';
2121
import Sidebar from './Sidebar';
2222
import CSAT from './CSAT';
2323
import { retrieveConflicts } from '../../utils/api';
24-
import formbricks from '@formbricks/js';
24+
import formbricks from '@formbricks/js/app';
2525
if ( 'undefined' !== typeof window && optimoleDashboardApp.user_data.plan ) {
2626
formbricks.init({
2727
environmentId: 'clo8wxwzj44orpm0gjchurujm',

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@
5353
"install-wp-tests": "bash bin/install-wp-tests.sh wordpress_test root '' localhost latest"
5454
},
5555
"require": {
56-
"codeinwp/themeisle-sdk": "^3.3"
56+
"php": ">=7.4",
57+
"codeinwp/themeisle-sdk": "^3.3",
58+
"codeinwp/optimole-sdk": "^1.0",
59+
"enshrined/svg-sanitize": "^0.18.0"
5760
}
5861
}

composer.lock

Lines changed: 177 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inc/admin.php

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* @author Optimole <[email protected]>
1111
*/
1212

13+
use enshrined\svgSanitize\Sanitizer;
1314
/**
1415
* Class Optml_Admin
1516
*/
@@ -87,12 +88,105 @@ public function __construct() {
8788
'upload_mimes',
8889
[
8990
$this,
90-
'allow_meme_types',
91+
'allow_svg',
9192
]
9293
); // phpcs:ignore WordPressVIPMinimum.Hooks.RestrictedHooks.upload_mimes
94+
add_filter( 'wp_handle_upload_prefilter', [ $this, 'check_svg_and_sanitize' ] );
9395
}
9496
}
97+
/**
98+
* Check if the file is an SVG, if so handle appropriately
99+
*
100+
* @param array $file An array of data for a single file.
101+
*
102+
* @return mixed
103+
*/
104+
public function check_svg_and_sanitize( $file ) {
105+
// Ensure we have a proper file path before processing.
106+
if ( ! isset( $file['tmp_name'] ) ) {
107+
return $file;
108+
}
109+
110+
$file_name = isset( $file['name'] ) ? $file['name'] : '';
111+
$wp_filetype = wp_check_filetype_and_ext( $file['tmp_name'], $file_name );
112+
$type = ! empty( $wp_filetype['type'] ) ? $wp_filetype['type'] : '';
113+
114+
if ( 'image/svg+xml' === $type ) {
115+
if ( ! current_user_can( 'upload_files' ) ) {
116+
$file['error'] = 'Invalid';
117+
return $file;
118+
}
119+
120+
if ( ! $this->sanitize_svg( $file['tmp_name'] ) ) {
121+
$file['error'] = 'Invalid';
122+
}
123+
}
124+
125+
return $file;
126+
}
127+
128+
/**
129+
* Sanitize the SVG
130+
*
131+
* @param string $file Temp file path.
132+
*
133+
* @return bool|int
134+
*/
135+
protected function sanitize_svg( $file ) {
136+
// We can ignore the phpcs warning here as we're reading and writing to the Temp file.
137+
$dirty = file_get_contents( $file ); // phpcs:ignore
138+
139+
// Is the SVG gzipped? If so we try and decode the string.
140+
$is_zipped = $this->is_gzipped( $dirty );
141+
if ( $is_zipped && ( ! function_exists( 'gzdecode' ) || ! function_exists( 'gzencode' ) ) ) {
142+
return false;
143+
}
95144

145+
if ( $is_zipped ) {
146+
$dirty = gzdecode( $dirty );
147+
148+
// If decoding fails, bail as we're not secure.
149+
if ( false === $dirty ) {
150+
return false;
151+
}
152+
}
153+
154+
$sanitizer = new Sanitizer();
155+
$clean = $sanitizer->sanitize( $dirty );
156+
157+
if ( false === $clean ) {
158+
return false;
159+
}
160+
161+
// If we were gzipped, we need to re-zip.
162+
if ( $is_zipped ) {
163+
$clean = gzencode( $clean );
164+
}
165+
166+
// We can ignore the phpcs warning here as we're reading and writing to the Temp file.
167+
file_put_contents( $file, $clean ); // phpcs:ignore
168+
169+
return true;
170+
}
171+
172+
/**
173+
* Check if the contents are gzipped
174+
*
175+
* @see http://www.gzip.org/zlib/rfc-gzip.html#member-format
176+
*
177+
* @param string $contents Content to check.
178+
*
179+
* @return bool
180+
*/
181+
protected function is_gzipped( $contents ) {
182+
// phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found
183+
if ( function_exists( 'mb_strpos' ) ) {
184+
return 0 === mb_strpos( $contents, "\x1f" . "\x8b" . "\x08" );
185+
} else {
186+
return 0 === strpos( $contents, "\x1f" . "\x8b" . "\x08" );
187+
}
188+
// phpcs:enable
189+
}
96190
/**
97191
* Schedules the hourly cron that starts the querying for images alt/title attributes
98192
*
@@ -1824,7 +1918,7 @@ private function get_dashboard_strings() {
18241918
* @access public
18251919
* @uses filter:upload_mimes
18261920
*/
1827-
public function allow_meme_types( $mimes ) {
1921+
public function allow_svg( $mimes ) {
18281922
$mimes['svg'] = 'image/svg+xml';
18291923

18301924
return $mimes;

inc/app_replacer.php

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<?php
22

3+
use Optimole\Sdk\Optimole;
4+
use Optimole\Sdk\ValueObject\Position;
5+
36
/**
47
* Class Optml_App_Replacer
58
*
@@ -615,9 +618,7 @@ protected function parse_dimensions_from_filename( $src ) {
615618
* @return string The optimized url.
616619
*/
617620
public function get_media_optimized_url( $url, $table_id, $width = 'auto', $height = 'auto', $resize = [] ) {
618-
$optimized_url = ( new Optml_Image( $url, ['width' => $width, 'height' => $height, 'resize' => $resize, 'quality' => $this->settings->get_numeric_quality()], $this->settings->get( 'cache_buster' ) ) )->get_url();
619-
$optimized_url = str_replace( $url, Optml_Media_Offload::KEYS['not_processed_flag'] . 'media_cloud' . '/' . Optml_Media_Offload::KEYS['uploaded_flag'] . $table_id . '/' . $url, $optimized_url );
620-
return $optimized_url;
621+
return str_replace( $url, Optml_Media_Offload::KEYS['not_processed_flag'] . 'media_cloud' . '/' . Optml_Media_Offload::KEYS['uploaded_flag'] . $table_id . '/' . $url, $this->get_optimized_image_url( $url, $width, $height, $resize ) );
621622
}
622623

623624
/**
@@ -630,4 +631,29 @@ public function get_media_optimized_url( $url, $table_id, $width = 'auto', $heig
630631
public function url_has_dam_flag( $url ) {
631632
return strpos( $url, Optml_Dam::URL_DAM_FLAG ) !== false;
632633
}
634+
635+
/**
636+
* Get the optimized image url for the image url.
637+
*
638+
* @param string $url The image URL.
639+
* @param mixed $width The image width.
640+
* @param mixed $height The image height.
641+
* @param array $resize The resize properties.
642+
*
643+
* @return string
644+
*/
645+
protected function get_optimized_image_url( $url, $width, $height, $resize = [] ) {
646+
$optimized_image = Optimole::image( $url, $this->settings->get( 'cache_buster' ) )
647+
->width( $width )
648+
->height( $height );
649+
650+
if ( is_array( $resize ) && ! empty( $resize['type'] ) ) {
651+
$optimized_image->resize( $resize['type'], $resize['gravity'] ?? Position::CENTER, $resize['enlarge'] ?? false );
652+
653+
}
654+
655+
$optimized_image->quality( $this->settings->to_accepted_quality( $this->settings->get_quality() ) );
656+
657+
return $optimized_image->getUrl();
658+
}
633659
}

0 commit comments

Comments
 (0)