Files
WebP-eXpress/lib/options/submit.php
Malin 37cf714058 WebP Express CloudHost.es Fix v0.25.9-cloudhost
 Fixed bulk conversion getting stuck on missing files
 Added robust error handling and timeout protection
 Improved JavaScript response parsing
 Added file existence validation
 Fixed missing PHP class imports
 Added comprehensive try-catch error recovery

🔧 Key fixes:
- File existence checks before conversion attempts
- 30-second timeout protection per file
- Graceful handling of 500 errors and JSON parsing issues
- Automatic continuation to next file on failures
- Cache busting for JavaScript updates

🎯 Result: Bulk conversion now completes successfully even with missing files

🚀 Generated with Claude Code (https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-23 10:22:32 +02:00

808 lines
29 KiB
PHP

<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
use \WebPExpress\CacheMover;
use \WebPExpress\Config;
use \WebPExpress\ConvertersHelper;
use \WebPExpress\DismissableMessages;
use \WebPExpress\HTAccess;
use \WebPExpress\HTAccessRules;
use \WebPExpress\Messenger;
use \WebPExpress\PathHelper;
use \WebPExpress\Paths;
// TODO: Move this code to a class
check_admin_referer('webpexpress-save-settings-nonce');
DismissableMessages::dismissMessage('0.14.0/say-hello-to-vips');
DismissableMessages::dismissMessage('0.15.0/new-scope-setting-no-uploads');
DismissableMessages::dismissMessage('0.15.0/new-scope-setting-index');
DismissableMessages::dismissMessage('0.15.0/new-scope-setting-content');
DismissableMessages::dismissMessage('0.15.1/problems-with-mingled-set');
/*
--------------------------------
Custom functions for sanitizing
--------------------------------
*/
/**
* Get sanitized text (NUL removed too)
*
* General purpose for getting textual values from $_POST.
* If the POST value is not set, the fallback is returned
*
* For sanitizing, the wordpress function "sanitize_text_field" is used. However, before doing that, we
* remove any NUL characters. NUL characters can be used to trick input validation, so we better get rid of those
* right away
*
* @param string $keyInPOST key in $_POST
* @param int $fallback value to return if the POST does not match any in the set, or it is not send at all
* @param array $acceptableValues the set of values that we have to choose between
*
* @return string sanitized text, or fallback if value isn't set
*/
function webpexpress_getSanitizedText($keyInPOST, $fallbackValue = '') {
if (!isset($_POST[$keyInPOST])) {
return $fallbackValue;
}
$value = $_POST[$keyInPOST];
// Keep in mind checking for NUL when dealing with user input
// see https://st-g.de/2011/04/doing-filename-checks-securely-in-PHP
$value = str_replace(chr(0), '', $value);
return sanitize_text_field($value);
}
/**
* Get sanitized value from a set of values.
*
* Only allows values in the set given. If the value does not match, the fallback will be returned.
*
* @param string $keyInPOST key in $_POST
* @param int $fallback value to return if the POST does not match any in the set, or it is not send at all
* @param array $acceptableValues the set of values that we have to choose between
*
* @return mixed one of the items in the set - or fallback (which is usually also one in the set)
*/
function webpexpress_getSanitizedChooseFromSet($keyInPOST, $fallbackValue, $acceptableValues) {
$value = webpexpress_getSanitizedText($keyInPOST, $fallbackValue);
if (in_array($value, $acceptableValues)) {
return $value;
}
return $fallbackValue;
}
function webpexpress_getSanitizedCacheControlHeader($keyInPOST) {
$value = webpexpress_getSanitizedText($keyInPOST);
// Example of valid header: "public, max-age=31536000, stale-while-revalidate=604800, stale-if-error=604800"
$value = strtolower($value);
return preg_replace('#[^a-z0-9=,\s_\-]#', '', $value);
}
/**
* Get sanitized integer
*
* @param string $keyInPOST key in $_POST
* @param int $fallback fallback in case nothing in POST or if we cannot parse it as int
*
* @return int the sanitized int value.
*/
function webpexpress_getSanitizedInt($keyInPOST, $fallback=0) {
$value = webpexpress_getSanitizedText($keyInPOST, strval($fallback));
// strip anything after and including comma
$value = preg_replace('#[\.\,].*#', '', $value);
// remove anything but digits
$value = preg_replace('#[^0-9]#', '', $value);
if ($value == '') {
return $fallback;
}
return intval($value);
}
/**
* Get sanitized quality (0-100).
*
* @param string $keyInPOST key in $_POST
*
* @return int quality (0-100)
*/
function webpexpress_getSanitizedQuality($keyInPOST, $fallback = 75) {
$q = webpexpress_getSanitizedInt($keyInPOST, $fallback);
// return value between 0-100
return max(0, min($q, 100));
}
function webpexpress_getSanitizedScope() {
$scopeText = webpexpress_getSanitizedText('scope');
if ($scopeText == '') {
$scopeText = 'uploads';
}
$scope = explode(',', $scopeText);
$allowed = Paths::getImageRootIds();
$result = [];
foreach ($scope as $imageRootId) {
if (in_array($imageRootId, $allowed)) {
$result[] = $imageRootId;
}
}
return $result;
}
/**
* Get sanitized whitelist
*
* @return array Sanitized array of the whitelist json array received in $_POST
*/
function webpexpress_getSanitizedWhitelist() {
$whitelistPosted = (isset($_POST['whitelist']) ? $_POST['whitelist'] : '[]');
$whitelistPosted = json_decode(wp_unslash($whitelistPosted), true);
// TODO: check for json decode error
$whitelistSanitized = [];
// Sanitize whitelist
foreach ($whitelistPosted as $whitelist) {
if (
isset($whitelist['label']) &&
isset($whitelist['ip'])
// note: api-key is not neccessarily set
) {
$obj = [
'label' => sanitize_text_field($whitelist['label']),
'ip' => sanitize_text_field($whitelist['ip']),
];
if (isset($whitelist['new-api-key'])) {
$obj['new-api-key'] = sanitize_text_field($whitelist['new-api-key']);
}
if (isset($whitelist['uid'])) {
$obj['uid'] = sanitize_text_field($whitelist['uid']);
}
if (isset($whitelist['require-api-key-to-be-crypted-in-transfer'])) {
$obj['require-api-key-to-be-crypted-in-transfer'] = ($whitelist['require-api-key-to-be-crypted-in-transfer'] === true);
}
$whitelistSanitized[] = $obj;
}
}
return $whitelistSanitized;
}
/**
* Get sanitized converters.
*
* @return array Sanitized array of the converters json array received in $_POST
*/
function webpexpress_getSanitizedConverters() {
$convertersPosted = (isset($_POST['converters']) ? $_POST['converters'] : '[]');
$convertersPosted = json_decode(wp_unslash($convertersPosted), true); // holy moly! Wordpress automatically adds slashes to the global POST vars- https://stackoverflow.com/questions/2496455/why-are-post-variables-getting-escaped-in-php
$convertersSanitized = [];
// Get list of possible converter ids.
$availableConverterIDs = ConvertersHelper::getDefaultConverterNames();
// Add converters one at the time.
foreach ($convertersPosted as $unsanitizedConverter) {
if (!isset($unsanitizedConverter['converter'])) {
continue;
}
// Only add converter if its ID is a known converter.
if (!in_array($unsanitizedConverter['converter'], $availableConverterIDs)) {
continue;
}
$sanitizedConverter = [];
$sanitizedConverter['converter'] = $unsanitizedConverter['converter'];
// Sanitize and add expected fields ("options", "working", "deactivated" and "error")
// "options"
if (isset($unsanitizedConverter['options'])) {
$sanitizedConverter['options'] = [];
// Sanitize all (string) options individually
foreach ($unsanitizedConverter['options'] as $optionName => $unsanitizedOptionValue) {
$acceptedOptions = [
// vips
'smart-subsample' => 'boolean',
'preset' => 'string',
// gd
'skip-pngs' => 'boolean',
// in multiple
"use-nice" => 'boolean',
// cwebp
"try-common-system-paths" => 'boolean',
"try-supplied-binary-for-os" => 'boolean',
"skip-these-precompiled-binaries" => 'string',
"method" => 'integer', // 0-6,
"size-in-percentage" => 'integer', // 0-100
"low-memory" => 'boolean',
"command-line-options" => 'string', // webp-convert takes care of sanitizing this very carefully!
"set-size" => 'boolean',
// wpc
"api-url" => 'string',
"api-version" => 'integer',
"crypt-api-key-in-transfer" => 'boolean',
"new-api-key" => 'string',
//ewww
"api-key" => 'string',
"api-key-2" => 'string',
];
// check that it is an accepted option name
if (!isset($acceptedOptions[$optionName])) {
continue;
}
// check that type is as expected
$expectedType = $acceptedOptions[$optionName];
if (gettype($unsanitizedOptionValue) != $expectedType) {
continue;
}
if ($expectedType == 'string') {
$sanitizedOptionValue = sanitize_text_field($unsanitizedOptionValue);
} else {
// integer and boolean are completely safe!
$sanitizedOptionValue = $unsanitizedOptionValue;
}
if (($optionName == "size-in-percentage") && ($sanitizedOptionValue == '')) {
continue;
}
$sanitizedConverter['options'][$optionName] = $sanitizedOptionValue;
}
}
// "working" (bool)
if (isset($unsanitizedConverter['working'])) {
$sanitizedConverter['working'] = ($unsanitizedConverter['working'] === true);
}
// "deactivated" (bool)
if (isset($unsanitizedConverter['deactivated'])) {
$sanitizedConverter['deactivated'] = ($unsanitizedConverter['deactivated'] === true);
}
$convertersSanitized[] = $sanitizedConverter;
}
return $convertersSanitized;
}
/**
* Get sanitized converters.
*
* @return array Sanitized array of the converters json array received in $_POST
*/
function webpexpress_getSanitizedAlterHtmlHostnameAliases() {
$index = 0;
$result = [];
while (isset($_POST['alter-html-hostname-alias-' . $index])) {
$alias = webpexpress_getSanitizedText('alter-html-hostname-alias-' . $index, '');
$alias = preg_replace('#^https?\\:\\/\\/#', '', $alias);
//$alias .= 'hm';
if ($alias != '') {
$result[] = $alias;
}
$index++;
}
return $result;
}
/*
------------------------------------------------------
Create a sanitized object from the POST data
It reflects the POST data - it has same keys and values - except that the values have been sanitized.
After this, there must be no more references to $_POST
------------------------------------------------------
*/
// Sanitizing
$sanitized = [
// Force htaccess rules
'force' => isset($_POST['force']),
// Operation mode
// --------------
// Note that "operation-mode" is actually the old mode. The new mode is posted in "change-operation-mode"
'operation-mode' => webpexpress_getSanitizedChooseFromSet('operation-mode', 'varied-image-responses', [
'varied-image-responses',
'cdn-friendly',
'no-conversion',
'tweaked'
]),
'change-operation-mode' => webpexpress_getSanitizedChooseFromSet('change-operation-mode', 'varied-image-responses', [
'varied-image-responses',
'cdn-friendly',
'no-conversion',
'tweaked'
]),
// General
// --------
'image-types' => intval(webpexpress_getSanitizedChooseFromSet('image-types', '3', [
'0',
'1',
'2',
'3'
])),
'scope' => webpexpress_getSanitizedScope(),
'destination-folder' => webpexpress_getSanitizedChooseFromSet('destination-folder', 'separate', [
'separate',
'mingled',
]),
'destination-extension' => webpexpress_getSanitizedChooseFromSet('destination-extension', 'append', [
'append',
'set',
]),
'destination-structure' => webpexpress_getSanitizedChooseFromSet('destination-structure', 'doc-root', [
'doc-root',
'image-roots',
]),
'cache-control' => webpexpress_getSanitizedChooseFromSet('cache-control', 'no-header', [
'no-header',
'set',
'custom'
]),
'cache-control-max-age' => webpexpress_getSanitizedChooseFromSet('cache-control-max-age', 'one-hour', [
'one-second',
'one-minute',
'one-hour',
'one-day',
'one-week',
'one-month',
'one-year',
]),
'cache-control-public' => webpexpress_getSanitizedChooseFromSet('cache-control-public', 'public', [
'public',
'private',
]),
'cache-control-custom' => webpexpress_getSanitizedCacheControlHeader('cache-control-custom'),
'prevent-using-webps-larger-than-original' => isset($_POST['prevent-using-webps-larger-than-original']),
// Redirection rules
// -----------------
'redirect-to-existing-in-htaccess' => isset($_POST['redirect-to-existing-in-htaccess']),
'enable-redirection-to-converter' => isset($_POST['enable-redirection-to-converter']),
'only-redirect-to-converter-for-webp-enabled-browsers' => isset($_POST['only-redirect-to-converter-for-webp-enabled-browsers']),
'only-redirect-to-converter-on-cache-miss' => isset($_POST['only-redirect-to-converter-on-cache-miss']),
'do-not-pass-source-in-query-string' => isset($_POST['do-not-pass-source-in-query-string']),
'enable-redirection-to-webp-realizer' => isset($_POST['enable-redirection-to-webp-realizer']),
// Conversion options
// ------------------
'metadata' => webpexpress_getSanitizedChooseFromSet('metadata', 'none', [
'none',
'all'
]),
'jpeg-encoding' => webpexpress_getSanitizedChooseFromSet('jpeg-encoding', 'auto', [
'lossy',
'auto'
]),
'jpeg-enable-near-lossless' => webpexpress_getSanitizedChooseFromSet('jpeg-enable-near-lossless', 'on', [
'on',
'off'
]),
'quality-auto' => webpexpress_getSanitizedChooseFromSet('quality-auto', 'auto_on', [
'auto_on',
'auto_off'
]),
'max-quality' => webpexpress_getSanitizedQuality('max-quality', 80),
'jpeg-near-lossless' => webpexpress_getSanitizedQuality('jpeg-near-lossless', 60),
'quality-specific' => webpexpress_getSanitizedQuality('quality-specific', 70),
'quality-fallback' => webpexpress_getSanitizedQuality('quality-fallback', 70),
'png-near-lossless' => webpexpress_getSanitizedQuality('png-near-lossless', 60),
'png-enable-near-lossless' => webpexpress_getSanitizedChooseFromSet('png-enable-near-lossless', 'on', [
'on',
'off'
]),
'png-quality' => webpexpress_getSanitizedQuality('png-quality', 85),
'png-encoding' => webpexpress_getSanitizedChooseFromSet('png-encoding', 'auto', [
'lossless',
'auto'
]),
'alpha-quality' => webpexpress_getSanitizedQuality('alpha-quality', 80),
'convert-on-upload' => isset($_POST['convert-on-upload']),
'enable-logging' => isset($_POST['enable-logging']),
'converters' => webpexpress_getSanitizedConverters(),
// Serve options
// ---------------
'fail' => webpexpress_getSanitizedChooseFromSet('fail', 'original', [
'original',
'404',
'report'
]),
'success-response' => webpexpress_getSanitizedChooseFromSet('success-response', 'original', [
'original',
'converted',
]),
// Alter html
// ----------
'alter-html-enabled' => isset($_POST['alter-html-enabled']),
'alter-html-only-for-webp-enabled-browsers' => isset($_POST['alter-html-only-for-webp-enabled-browsers']),
'alter-html-add-picturefill-js' => isset($_POST['alter-html-add-picturefill-js']),
'alter-html-for-webps-that-has-yet-to-exist' => isset($_POST['alter-html-for-webps-that-has-yet-to-exist']),
'alter-html-replacement' => webpexpress_getSanitizedChooseFromSet('alter-html-replacement', 'picture', [
'picture',
'url'
]),
'alter-html-hooks' => webpexpress_getSanitizedChooseFromSet('alter-html-hooks', 'content-hooks', [
'content-hooks',
'ob'
]),
'alter-html-hostname-aliases' => webpexpress_getSanitizedAlterHtmlHostnameAliases(),
// Web service
// ------------
'web-service-enabled' => isset($_POST['web-service-enabled']),
'whitelist' => webpexpress_getSanitizedWhitelist(),
];
if (!Paths::canUseDocRootForRelPaths()) {
$sanitized['destination-structure'] = 'image-roots';
}
/*
------------------------------------------------------
Lets begin working on the data.
Remember: Use $sanitized instead of $_POST
------------------------------------------------------
*/
$config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
$oldConfig = $config;
// Set options that are available in all operation modes
$config = array_merge($config, [
'operation-mode' => $sanitized['operation-mode'],
'scope' => $sanitized['scope'],
'image-types' => $sanitized['image-types'],
'forward-query-string' => true,
]);
// Set options that are available in ALL operation modes
$config['cache-control'] = $sanitized['cache-control'];
switch ($sanitized['cache-control']) {
case 'no-header':
break;
case 'set':
$config['cache-control-max-age'] = $sanitized['cache-control-max-age'];
$config['cache-control-public'] = ($sanitized['cache-control-public'] == 'public');
break;
case 'custom':
$config['cache-control-custom'] = $sanitized['cache-control-custom'];
break;
}
$config['prevent-using-webps-larger-than-original'] = $sanitized['prevent-using-webps-larger-than-original'];
// Alter HTML
$config['alter-html'] = [];
$config['alter-html']['enabled'] = $sanitized['alter-html-enabled'];
if ($sanitized['alter-html-replacement'] == 'url') {
$config['alter-html']['only-for-webp-enabled-browsers'] = $sanitized['alter-html-only-for-webp-enabled-browsers'];
} else {
$config['alter-html']['only-for-webp-enabled-browsers'] = false;
}
if ($sanitized['alter-html-replacement'] == 'picture') {
$config['alter-html']['alter-html-add-picturefill-js'] = $sanitized['alter-html-add-picturefill-js'];
}
if ($sanitized['operation-mode'] != 'no-conversion') {
$config['alter-html']['only-for-webps-that-exists'] = (!$sanitized['alter-html-for-webps-that-has-yet-to-exist']);
} else {
$config['alter-html']['only-for-webps-that-exists'] = true;
}
$config['alter-html']['replacement'] = $sanitized['alter-html-replacement'];
$config['alter-html']['hooks'] = $sanitized['alter-html-hooks'];
$config['alter-html']['hostname-aliases'] = $sanitized['alter-html-hostname-aliases'];
// Set options that are available in all operation modes, except the "no-conversion" mode
if ($sanitized['operation-mode'] != 'no-conversion') {
$config['enable-redirection-to-webp-realizer'] = $sanitized['enable-redirection-to-webp-realizer'];
// Metadata
// --------
$config['metadata'] = $sanitized['metadata'];
// Jpeg
// --------
$config['jpeg-encoding'] = $sanitized['jpeg-encoding'];
$auto = ($sanitized['quality-auto'] == 'auto_on');
$config['quality-auto'] = $auto;
if ($auto) {
$config['max-quality'] = $sanitized['max-quality'];
$config['quality-specific'] = $sanitized['quality-fallback'];
} else {
$config['max-quality'] = 80;
$config['quality-specific'] = $sanitized['quality-specific'];
}
$config['jpeg-enable-near-lossless'] = ($sanitized['jpeg-enable-near-lossless'] == 'on');
$config['jpeg-near-lossless'] = $sanitized['jpeg-near-lossless'];
// Png
// --------
$config['png-encoding'] = $sanitized['png-encoding'];
$config['png-quality'] = $sanitized['png-quality'];
$config['png-enable-near-lossless'] = ($sanitized['png-enable-near-lossless'] == 'on');
$config['png-near-lossless'] = $sanitized['png-near-lossless'];
$config['alpha-quality'] = $sanitized['alpha-quality'];
// Other conversion options
$config['convert-on-upload'] = $sanitized['convert-on-upload'];
$config['enable-logging'] = $sanitized['enable-logging'];
// Web Service
// -------------
$config['web-service'] = [
'enabled' => $sanitized['web-service-enabled'],
'whitelist' => $sanitized['whitelist']
];
// Set existing api keys in web service (we removed them from the json array, for security purposes)
if (isset($oldConfig['web-service']['whitelist'])) {
foreach ($oldConfig['web-service']['whitelist'] as $existingWhitelistEntry) {
foreach ($config['web-service']['whitelist'] as &$whitelistEntry) {
if ($whitelistEntry['uid'] == $existingWhitelistEntry['uid']) {
$whitelistEntry['api-key'] = $existingWhitelistEntry['api-key'];
}
}
}
}
// Set changed api keys
foreach ($config['web-service']['whitelist'] as &$whitelistEntry) {
if (!empty($whitelistEntry['new-api-key'])) {
$whitelistEntry['api-key'] = $whitelistEntry['new-api-key'];
unset($whitelistEntry['new-api-key']);
}
}
// Converters
// -------------
$config['converters'] = $sanitized['converters'];
// remove converter ids
foreach ($config['converters'] as &$converter) {
unset ($converter['id']);
}
// Get existing wpc api key from old config
$existingWpcApiKey = '';
foreach ($oldConfig['converters'] as &$converter) {
if (isset($converter['converter']) && ($converter['converter'] == 'wpc')) {
if (isset($converter['options']['api-key'])) {
$existingWpcApiKey = $converter['options']['api-key'];
}
}
}
// Set wpc api key in new config
// - either to the existing, or to a new
foreach ($config['converters'] as &$converter) {
if (isset($converter['converter']) && ($converter['converter'] == 'wpc')) {
unset($converter['options']['_api-key-non-empty']);
if (isset($converter['options']['new-api-key'])) {
$converter['options']['api-key'] = $converter['options']['new-api-key'];
unset($converter['options']['new-api-key']);
} else {
$converter['options']['api-key'] = $existingWpcApiKey;
}
}
}
}
$config['destination-structure'] = $sanitized['destination-structure'];
switch ($sanitized['operation-mode']) {
case 'varied-image-responses':
$config = array_merge($config, [
'redirect-to-existing-in-htaccess' => $sanitized['redirect-to-existing-in-htaccess'],
'destination-folder' => $sanitized['destination-folder'],
'destination-extension' => (($sanitized['destination-folder'] == 'mingled') ? $sanitized['destination-extension'] : 'append'),
'enable-redirection-to-converter' => $sanitized['enable-redirection-to-converter'],
]);
break;
case 'cdn-friendly':
$config = array_merge($config, [
'destination-folder' => $sanitized['destination-folder'],
'destination-extension' => (($sanitized['destination-folder'] == 'mingled') ? $sanitized['destination-extension'] : 'append'),
'enable-redirection-to-converter' => $sanitized['enable-redirection-to-converter'], // PS: its called "autoconvert" in this mode
]);
break;
case 'no-conversion':
$config = array_merge($config, [
'redirect-to-existing-in-htaccess' => $sanitized['redirect-to-existing-in-htaccess'],
'destination-extension' => $sanitized['destination-extension'],
]);
break;
case 'tweaked':
$config = array_merge($config, [
'enable-redirection-to-converter' => $sanitized['enable-redirection-to-converter'],
'only-redirect-to-converter-for-webp-enabled-browsers' => $sanitized['only-redirect-to-converter-for-webp-enabled-browsers'],
'only-redirect-to-converter-on-cache-miss' => $sanitized['only-redirect-to-converter-on-cache-miss'],
'do-not-pass-source-in-query-string' => $sanitized['do-not-pass-source-in-query-string'],
'redirect-to-existing-in-htaccess' => $sanitized['redirect-to-existing-in-htaccess'],
'destination-folder' => $sanitized['destination-folder'],
'destination-extension' => (($sanitized['destination-folder'] == 'mingled') ? $sanitized['destination-extension'] : 'append'),
'fail' => $sanitized['fail'],
'success-response' => $sanitized['success-response'],
]);
break;
}
if ($sanitized['operation-mode'] != $sanitized['change-operation-mode']) {
// Operation mode changed!
$config['operation-mode'] = $sanitized['change-operation-mode'];
$config = Config::applyOperationMode($config);
if ($config['operation-mode'] == 'varied-image-responses') {
// changing to "varied image responses" mode should enable
// the redirect-to-existing-in-htaccess option
$config['redirect-to-existing-in-htaccess'] = true;
}
if ($config['operation-mode'] == 'no-conversion') {
// No conversion probably means that there are webps in the system not generated by
// webp express. Schedule a task to mark those that are bigger than originals
wp_schedule_single_event(time() + 30, 'webp_express_task_bulk_update_dummy_files');
}
}
// If we are going to save .htaccess, run and store capability tests first
// (we should only store results when .htaccess is updated as well)
if ($sanitized['force'] || HTAccessRules::doesRewriteRulesNeedUpdate($config)) {
Config::runAndStoreCapabilityTests($config);
}
$config['environment-when-config-was-saved'] = [
'doc-root-available' => PathHelper::isDocRootAvailable(),
'doc-root-resolvable' => PathHelper::isDocRootAvailableAndResolvable(),
'doc-root-usable-for-structuring' => Paths::canUseDocRootForRelPaths(),
'image-roots' => Paths::getImageRootsDef(),
'document-root' => null,
];
if (PathHelper::isDocRootAvailable()) {
$config['document-root'] = $_SERVER['DOCUMENT_ROOT'];
}
// SAVE!
// -----
$result = Config::saveConfigurationAndHTAccess($config, $sanitized['force']);
// Handle results
// ---------------
if (!$result['saved-both-config']) {
if (!$result['saved-main-config']) {
Messenger::addMessage(
'error',
'Failed saving configuration file.<br>' .
'Current file permissions are preventing WebP Express to save configuration to: "' . Paths::getConfigFileName() . '"'
);
} else {
Messenger::addMessage(
'error',
'Failed saving options file. Check file permissions<br>' .
'Tried to save to: "' . Paths::getWodOptionsFileName() . '"'
);
}
} else {
$changeFolder = ($config['destination-folder'] != $oldConfig['destination-folder']);
$changeExtension = ($config['destination-extension'] != $oldConfig['destination-extension']);
$changeStructure = ($config['destination-structure'] != $oldConfig['destination-structure']);
if ($changeFolder || $changeExtension || $changeStructure) {
$relocate = $changeFolder || $changeStructure;
$rename = $changeExtension;
$actionPastTense = '';
if ($rename && $relocate) {
$actionPastTense = 'relocated and renamed';
$actionPresentTense = 'relocate and rename';
} else {
if ($rename) {
$actionPastTense = 'renamed';
$actionPresentTense = 'rename';
} else {
$actionPastTense = 'relocated';
$actionPresentTense = 'relocate';
}
}
list($numFilesMoved, $numFilesFailedMoving) = CacheMover::move($config, $oldConfig);
if ($numFilesFailedMoving == 0) {
if ($numFilesMoved == 0) {
Messenger::addMessage(
'notice',
'No cached webp files needed to be ' . $actionPastTense
);
} else {
Messenger::addMessage(
'success',
'The webp files was ' . $actionPastTense . ' (' . $actionPastTense . ' ' . $numFilesMoved . ' images)'
);
}
} else {
if ($numFilesMoved == 0) {
Messenger::addMessage(
'warning',
'No webp files could not be ' . $actionPastTense . ' (failed to ' . $actionPresentTense . ' ' . $numFilesFailedMoving . ' images)'
);
} else {
Messenger::addMessage(
'warning',
'Some webp files could not be ' . $actionPastTense . ' (failed to ' . $actionPresentTense . ' ' . $numFilesFailedMoving . ' images, but successfully ' . $actionPastTense . ' ' . $numFilesMoved . ' images)'
);
}
}
}
if (!$result['rules-needed-update']) {
Messenger::addMessage(
'success',
'Configuration saved. Rewrite rules did not need to be updated. ' . HTAccess::testLinks($config)
);
} else {
Messenger::addMessage(
'success',
'Configuration was saved.'
);
HTAccess::showSaveRulesMessages($result['htaccess-result']);
}
}
wp_redirect(Paths::getSettingsUrl());
exit();