Fixed many WPCS warnings

This fixes or explicitly ignores most - but not all - coding standard issues that are reported when running PHP_CodeSniffer with the basic WordPress ruleset and the WordPress-VIP ruleset. 

Notably, one of the issues that remain is the request timeout for update requests and VCS API requests. The current default is 10 seconds, but the WordPress-VIP standards appear to require 3 seconds or less. Personally, I'm not sure if that low limit is appropriate for requests that are intended to mostly run in Cron jobs.
This commit is contained in:
Yahnis Elsts 2022-10-14 19:37:00 +03:00
parent 6c9fce0887
commit 749f33c5c4
12 changed files with 75 additions and 40 deletions

View File

@ -66,14 +66,16 @@ if ( !class_exists(Extension::class, false) ):
* the update checking process works as expected.
*/
public function ajaxCheckNow() {
if ( $_POST['uid'] !== $this->updateChecker->getUniqueName('uid') ) {
//phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is checked in preAjaxRequest().
if ( !isset($_POST['uid']) || ($_POST['uid'] !== $this->updateChecker->getUniqueName('uid')) ) {
return;
}
$this->preAjaxRequest();
$update = $this->updateChecker->checkForUpdates();
if ( $update !== null ) {
echo "An update is available:";
echo '<pre>', htmlentities(print_r($update, true)), '</pre>';
//phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- For debugging output.
echo '<pre>', esc_html(print_r($update, true)), '</pre>';
} else {
echo 'No updates found.';
}
@ -85,7 +87,7 @@ if ( !class_exists(Extension::class, false) ):
foreach (array_values($errors) as $num => $item) {
$wpError = $item['error'];
/** @var \WP_Error $wpError */
printf('<h4>%d) %s</h4>', $num + 1, esc_html($wpError->get_error_message()));
printf('<h4>%d) %s</h4>', intval($num + 1), esc_html($wpError->get_error_message()));
echo '<dl>';
printf('<dt>Error code:</dt><dd><code>%s</code></dd>', esc_html($wpError->get_error_code()));
@ -107,8 +109,8 @@ if ( !class_exists(Extension::class, false) ):
//Status code.
printf(
'<dt>HTTP status:</dt><dd><code>%d %s</code></dd>',
wp_remote_retrieve_response_code($item['httpResponse']),
wp_remote_retrieve_response_message($item['httpResponse'])
esc_html(wp_remote_retrieve_response_code($item['httpResponse'])),
esc_html(wp_remote_retrieve_response_message($item['httpResponse']))
);
//Headers.
@ -147,7 +149,9 @@ if ( !class_exists(Extension::class, false) ):
}
check_ajax_referer('puc-ajax');
//phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting -- Part of a debugging feature.
error_reporting(E_ALL);
//phpcs:ignore WordPress.PHP.IniSet.display_errors_Blacklisted
@ini_set('display_errors', 'On');
}

View File

@ -20,14 +20,16 @@ if ( !class_exists(PluginExtension::class, false) ):
* Request plugin info and output it.
*/
public function ajaxRequestInfo() {
if ( $_POST['uid'] !== $this->updateChecker->getUniqueName('uid') ) {
//phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is checked in preAjaxRequest().
if ( !isset($_POST['uid']) || ($_POST['uid'] !== $this->updateChecker->getUniqueName('uid')) ) {
return;
}
$this->preAjaxRequest();
$info = $this->updateChecker->requestInfo();
if ( $info !== null ) {
echo 'Successfully retrieved plugin info from the metadata URL:';
echo '<pre>', htmlentities(print_r($info, true)), '</pre>';
//phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- For debugging output.
echo '<pre>', esc_html(print_r($info, true)), '</pre>';
} else {
echo 'Failed to retrieve plugin info from the metadata URL.';
}

View File

@ -36,16 +36,18 @@ if ( !class_exists(Metadata::class, false) ):
/** @var \StdClass $apiResponse */
$apiResponse = json_decode($json);
if ( empty($apiResponse) || !is_object($apiResponse) ){
$errorMessage = "Failed to parse update metadata. Try validating your .json file with http://jsonlint.com/";
$errorMessage = "Failed to parse update metadata. Try validating your .json file with https://jsonlint.com/";
do_action('puc_api_error', new WP_Error('puc-invalid-json', $errorMessage));
trigger_error($errorMessage, E_USER_NOTICE);
//phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error -- For plugin developers.
trigger_error(esc_html($errorMessage), E_USER_NOTICE);
return false;
}
$valid = $target->validateMetadata($apiResponse);
if ( is_wp_error($valid) ){
do_action('puc_api_error', $valid);
trigger_error($valid->get_error_message(), E_USER_NOTICE);
//phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error -- For plugin developers.
trigger_error(esc_html($valid->get_error_message()), E_USER_NOTICE);
return false;
}

View File

@ -26,10 +26,10 @@ if ( !class_exists(OAuthSignature::class, false) ):
$parameters = array();
//Parse query parameters.
$query = parse_url($url, PHP_URL_QUERY);
$query = wp_parse_url($url, PHP_URL_QUERY);
if ( !empty($query) ) {
parse_str($query, $parsedParams);
if ( is_array($parameters) ) {
if ( is_array($parsedParams) ) {
$parameters = $parsedParams;
}
//Remove the query string from the URL. We'll replace it later.
@ -91,7 +91,8 @@ if ( !class_exists(OAuthSignature::class, false) ):
}
}
if ( $rand === null ) {
$rand = mt_rand();
//phpcs:ignore WordPress.WP.AlternativeFunctions.rand_mt_rand
$rand = function_exists('wp_rand') ? wp_rand() : mt_rand();
}
return md5($mt . '_' . $rand);

View File

@ -206,8 +206,9 @@ if ( !class_exists('Ui', false) ):
* You can change the result message by using the "puc_manual_check_message-$slug" filter.
*/
public function displayManualCheckResult() {
//phpcs:disable WordPress.Security.NonceVerification.Recommended -- Just displaying a message.
if ( isset($_GET['puc_update_check_result'], $_GET['puc_slug']) && ($_GET['puc_slug'] == $this->updateChecker->slug) ) {
$status = strval($_GET['puc_update_check_result']);
$status = sanitize_key($_GET['puc_update_check_result']);
$title = $this->updateChecker->getInstalledPackage()->getPluginTitle();
$noticeClass = 'updated notice-success';
$details = '';
@ -223,16 +224,29 @@ if ( !class_exists('Ui', false) ):
$details = $this->formatManualCheckErrors(get_site_transient($this->manualCheckErrorTransient));
delete_site_transient($this->manualCheckErrorTransient);
} else {
$message = sprintf(__('Unknown update checker status "%s"', 'plugin-update-checker'), htmlentities($status));
$message = sprintf(__('Unknown update checker status "%s"', 'plugin-update-checker'), $status);
$noticeClass = 'error notice-error';
}
$message = esc_html($message);
//Plugins can replace the message with their own, including adding HTML.
$message = apply_filters(
$this->updateChecker->getUniqueName('manual_check_message'),
$message,
$status
);
printf(
'<div class="notice %s is-dismissible"><p>%s</p>%s</div>',
$noticeClass,
apply_filters($this->updateChecker->getUniqueName('manual_check_message'), $message, $status),
esc_attr($noticeClass),
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Was escaped above, and plugins can add HTML.
$message,
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Contains HTML. Content should already be escaped.
$details
);
}
//phpcs:enable
}
/**
@ -259,8 +273,8 @@ if ( !class_exists('Ui', false) ):
/** @var \WP_Error $wpError */
$output .= sprintf(
$formatString,
$wpError->get_error_message(),
$wpError->get_error_code()
esc_html($wpError->get_error_message()),
esc_html($wpError->get_error_code())
);
}
if ( $showAsList ) {

View File

@ -57,8 +57,8 @@ if ( !class_exists(UpdateChecker::class, false) ):
if ( $slugUsedBy ) {
$this->triggerError(sprintf(
'Plugin slug "%s" is already in use by %s. Slugs must be unique.',
htmlentities($slug),
htmlentities($slugUsedBy)
$slug,
$slugUsedBy
), E_USER_ERROR);
}
add_filter($slugCheckFilter, array($this, 'getAbsolutePath'));

View File

@ -105,13 +105,14 @@ if ( !class_exists(PucFactory::class, false) ):
$checkerClass = self::getCompatibleClassVersion($checkerClass);
if ( $checkerClass === null ) {
//phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
trigger_error(
sprintf(
esc_html(sprintf(
'PUC %s does not support updates for %ss %s',
htmlentities(self::$latestCompatibleVersion),
self::$latestCompatibleVersion,
strtolower($type),
$service ? ('hosted on ' . htmlentities($service)) : 'using JSON metadata'
),
$service ? ('hosted on ' . $service) : 'using JSON metadata'
)),
E_USER_ERROR
);
}
@ -123,11 +124,12 @@ if ( !class_exists(PucFactory::class, false) ):
//VCS checker + an API client.
$apiClass = self::getCompatibleClassVersion($apiClass);
if ( $apiClass === null ) {
trigger_error(sprintf(
//phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
trigger_error(esc_html(sprintf(
'PUC %s does not support %s',
htmlentities(self::$latestCompatibleVersion),
htmlentities($service)
), E_USER_ERROR);
self::$latestCompatibleVersion,
$service
)), E_USER_ERROR);
}
return new $checkerClass(
@ -251,8 +253,8 @@ if ( !class_exists(PucFactory::class, false) ):
$service = null;
//Which hosting service does the URL point to?
$host = (string)(parse_url($metadataUrl, PHP_URL_HOST));
$path = (string)(parse_url($metadataUrl, PHP_URL_PATH));
$host = (string)(wp_parse_url($metadataUrl, PHP_URL_HOST));
$path = (string)(wp_parse_url($metadataUrl, PHP_URL_PATH));
//Check if the path looks like "/user-name/repository".
//For GitLab.com it can also be "/user/group1/group2/.../repository".

View File

@ -57,7 +57,15 @@ if ( !class_exists(Scheduler::class, false) ):
if ( !wp_next_scheduled($this->cronHook) && !defined('WP_INSTALLING') ) {
//Randomly offset the schedule to help prevent update server traffic spikes. Without this
//most checks may happen during times of day when people are most likely to install new plugins.
$firstCheckTime = time() - rand(0, max($this->checkPeriod * 3600 - 15 * 60, 1));
$upperLimit = max($this->checkPeriod * 3600 - 15 * 60, 1);
if ( function_exists('wp_rand') ) {
$randomOffset = wp_rand(0, $upperLimit);
} else {
//This constructor may be called before wp_rand() is available.
//phpcs:ignore WordPress.WP.AlternativeFunctions.rand_rand
$randomOffset = rand(0, $upperLimit);
}
$firstCheckTime = time() - $randomOffset;
$firstCheckTime = apply_filters(
$this->updateChecker->getUniqueName('first_check_time'),
$firstCheckTime

View File

@ -210,7 +210,7 @@ if ( !class_exists(UpdateChecker::class, false) ):
*/
public function allowMetadataHost($allow, $host) {
if ( $this->cachedMetadataHost === 0 ) {
$this->cachedMetadataHost = parse_url($this->metadataUrl, PHP_URL_HOST);
$this->cachedMetadataHost = wp_parse_url($this->metadataUrl, PHP_URL_HOST);
}
if ( is_string($this->cachedMetadataHost) && (strtolower($host) === strtolower($this->cachedMetadataHost)) ) {
@ -432,7 +432,8 @@ if ( !class_exists(UpdateChecker::class, false) ):
*/
public function triggerError($message, $errorType) {
if ( $this->isDebugModeEnabled() ) {
trigger_error($message, $errorType);
//phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error -- Only happens in debug mode.
trigger_error(esc_html($message), $errorType);
}
}

View File

@ -24,7 +24,7 @@ if ( !class_exists(BitBucketApi::class, false) ):
private $repository;
public function __construct($repositoryUrl, $credentials = array()) {
$path = parse_url($repositoryUrl, PHP_URL_PATH);
$path = wp_parse_url($repositoryUrl, PHP_URL_PATH);
if ( preg_match('@^/?(?P<username>[^/]+?)/(?P<repository>[^/#?&]+?)/?$@', $path, $matches) ) {
$this->username = $matches['username'];
$this->repository = $matches['repository'];

View File

@ -46,7 +46,7 @@ if ( !class_exists(GitHubApi::class, false) ):
private $downloadFilterAdded = false;
public function __construct($repositoryUrl, $accessToken = null) {
$path = parse_url($repositoryUrl, PHP_URL_PATH);
$path = wp_parse_url($repositoryUrl, PHP_URL_PATH);
if ( preg_match('@^/?(?P<username>[^/]+?)/(?P<repository>[^/#?&]+?)/?$@', $path, $matches) ) {
$this->userName = $matches['username'];
$this->repositoryName = $matches['repository'];
@ -371,6 +371,7 @@ if ( !class_exists(GitHubApi::class, false) ):
*/
public function addHttpRequestFilter($result) {
if ( !$this->downloadFilterAdded && $this->isAuthenticationEnabled() ) {
//phpcs:ignore WordPressVIPMinimum.Hooks.RestrictedHooks.http_request_args -- The callback doesn't change the timeout.
add_filter('http_request_args', array($this, 'setUpdateDownloadHeaders'), 10, 2);
add_action('requests-requests.before_redirect', array($this, 'removeAuthHeaderFromRedirects'), 10, 4);
$this->downloadFilterAdded = true;

View File

@ -41,18 +41,18 @@ if ( !class_exists(GitLabApi::class, false) ):
public function __construct($repositoryUrl, $accessToken = null, $subgroup = null) {
//Parse the repository host to support custom hosts.
$port = parse_url($repositoryUrl, PHP_URL_PORT);
$port = wp_parse_url($repositoryUrl, PHP_URL_PORT);
if ( !empty($port) ) {
$port = ':' . $port;
}
$this->repositoryHost = parse_url($repositoryUrl, PHP_URL_HOST) . $port;
$this->repositoryHost = wp_parse_url($repositoryUrl, PHP_URL_HOST) . $port;
if ( $this->repositoryHost !== 'gitlab.com' ) {
$this->repositoryProtocol = parse_url($repositoryUrl, PHP_URL_SCHEME);
$this->repositoryProtocol = wp_parse_url($repositoryUrl, PHP_URL_SCHEME);
}
//Find the repository information
$path = parse_url($repositoryUrl, PHP_URL_PATH);
$path = wp_parse_url($repositoryUrl, PHP_URL_PATH);
if ( preg_match('@^/?(?P<username>[^/]+?)/(?P<repository>[^/#?&]+?)/?$@', $path, $matches) ) {
$this->userName = $matches['username'];
$this->repositoryName = $matches['repository'];