Skip to content

Commit

Permalink
Extract file parsing and lookup as a separate "Package" class.
Browse files Browse the repository at this point in the history
  • Loading branch information
YahnisElsts committed Jul 17, 2018
1 parent 98ac494 commit 4f6afa9
Show file tree
Hide file tree
Showing 9 changed files with 413 additions and 227 deletions.
103 changes: 103 additions & 0 deletions Puc/v4p4/InstalledPackage.php
@@ -0,0 +1,103 @@
<?php
if ( !class_exists('Puc_v4p4_InstalledPackage', false) ):

/**
* This class represents a currently installed plugin or theme.
*
* Not to be confused with the "package" field in WP update API responses that contains
* the download URL of a the new version.
*/
abstract class Puc_v4p4_InstalledPackage {
/**
* @var Puc_v4p4_UpdateChecker
*/
protected $updateChecker;

public function __construct($updateChecker) {
$this->updateChecker = $updateChecker;
}

/**
* Get the currently installed version of the plugin or theme.
*
* @return string|null Version number.
*/
abstract public function getInstalledVersion();

/**
* Get the full path of the plugin or theme directory (without a trailing slash).
*
* @return string
*/
abstract public function getAbsoluteDirectoryPath();

/**
* Check whether a regular file exists in the package's directory.
*
* @param string $relativeFileName File name relative to the package directory.
* @return bool
*/
public function fileExists($relativeFileName) {
return is_file(
$this->getAbsoluteDirectoryPath()
. DIRECTORY_SEPARATOR
. ltrim($relativeFileName, '/\\')
);
}

/* -------------------------------------------------------------------
* File header parsing
* -------------------------------------------------------------------
*/

/**
* Parse plugin or theme metadata from the header comment.
*
* This is basically a simplified version of the get_file_data() function from /wp-includes/functions.php.
* It's intended as a utility for subclasses that detect updates by parsing files in a VCS.
*
* @param string|null $content File contents.
* @return string[]
*/
public function getFileHeader($content) {
$content = (string)$content;

//WordPress only looks at the first 8 KiB of the file, so we do the same.
$content = substr($content, 0, 8192);
//Normalize line endings.
$content = str_replace("\r", "\n", $content);

$headers = $this->getHeaderNames();
$results = array();
foreach ($headers as $field => $name) {
$success = preg_match('/^[ \t\/*#@]*' . preg_quote($name, '/') . ':(.*)$/mi', $content, $matches);

if ( ($success === 1) && $matches[1] ) {
$value = $matches[1];
if ( function_exists('_cleanup_header_comment') ) {
$value = _cleanup_header_comment($value);
}
$results[$field] = $value;
} else {
$results[$field] = '';
}
}

return $results;
}

/**
* @return array Format: ['HeaderKey' => 'Header Name']
*/
abstract protected function getHeaderNames();

/**
* Get the value of a specific plugin or theme header.
*
* @param string $headerName
* @return string Either the value of the header, or an empty string if the header doesn't exist.
*/
abstract public function getHeaderValue($headerName);

}
endif;
174 changes: 174 additions & 0 deletions Puc/v4p4/Plugin/Package.php
@@ -0,0 +1,174 @@
<?php
if ( !class_exists('Puc_v4p4_Plugin_Package', false) ):

class Puc_v4p4_Plugin_Package extends Puc_v4p4_InstalledPackage {
/**
* @var Puc_v4p4_Plugin_UpdateChecker
*/
protected $updateChecker;

/**
* @var string Full path of the main plugin file.
*/
protected $pluginAbsolutePath = '';

/**
* @var string Plugin basename.
*/
private $pluginFile;

/**
* @var string|null
*/
private $cachedInstalledVersion = null;

public function __construct($pluginAbsolutePath, $updateChecker) {
$this->pluginAbsolutePath = $pluginAbsolutePath;
$this->pluginFile = plugin_basename($this->pluginAbsolutePath);

parent::__construct($updateChecker);

//Clear the version number cache when something - anything - is upgraded or WP clears the update cache.
add_filter('upgrader_post_install', array($this, 'clearCachedVersion'));
add_action('delete_site_transient_update_plugins', array($this, 'clearCachedVersion'));
}

public function getInstalledVersion() {
if ( isset($this->cachedInstalledVersion) ) {
return $this->cachedInstalledVersion;
}

$pluginHeader = $this->getPluginHeader();
if ( isset($pluginHeader['Version']) ) {
$this->cachedInstalledVersion = $pluginHeader['Version'];
return $pluginHeader['Version'];
} else {
//This can happen if the filename points to something that is not a plugin.
$this->updateChecker->triggerError(
sprintf(
"Can't to read the Version header for '%s'. The filename is incorrect or is not a plugin.",
$this->updateChecker->pluginFile
),
E_USER_WARNING
);
return null;
}
}

/**
* Clear the cached plugin version. This method can be set up as a filter (hook) and will
* return the filter argument unmodified.
*
* @param mixed $filterArgument
* @return mixed
*/
public function clearCachedVersion($filterArgument = null) {
$this->cachedInstalledVersion = null;
return $filterArgument;
}

public function getAbsoluteDirectoryPath() {
return dirname($this->pluginAbsolutePath);
}

/**
* Get the value of a specific plugin or theme header.
*
* @param string $headerName
* @param string $defaultValue
* @return string Either the value of the header, or $defaultValue if the header doesn't exist or is empty.
*/
public function getHeaderValue($headerName, $defaultValue = '') {
$headers = $this->getPluginHeader();
if ( isset($headers[$headerName]) && ($headers[$headerName] !== '') ) {
return $headers[$headerName];
}
return $defaultValue;
}

protected function getHeaderNames() {
return array(
'Name' => 'Plugin Name',
'PluginURI' => 'Plugin URI',
'Version' => 'Version',
'Description' => 'Description',
'Author' => 'Author',
'AuthorURI' => 'Author URI',
'TextDomain' => 'Text Domain',
'DomainPath' => 'Domain Path',
'Network' => 'Network',

//The newest WordPress version that this plugin requires or has been tested with.
//We support several different formats for compatibility with other libraries.
'Tested WP' => 'Tested WP',
'Requires WP' => 'Requires WP',
'Tested up to' => 'Tested up to',
'Requires at least' => 'Requires at least',
);
}

/**
* Get the translated plugin title.
*
* @return string
*/
public function getPluginTitle() {
$title = '';
$header = $this->getPluginHeader();
if ( $header && !empty($header['Name']) && isset($header['TextDomain']) ) {
$title = translate($header['Name'], $header['TextDomain']);
}
return $title;
}

/**
* Get plugin's metadata from its file header.
*
* @return array
*/
public function getPluginHeader() {
if ( !is_file($this->pluginAbsolutePath) ) {
//This can happen if the plugin filename is wrong.
$this->updateChecker->triggerError(
sprintf(
"Can't to read the plugin header for '%s'. The file does not exist.",
$this->updateChecker->pluginFile
),
E_USER_WARNING
);
return array();
}

if ( !function_exists('get_plugin_data') ) {
/** @noinspection PhpIncludeInspection */
require_once(ABSPATH . '/wp-admin/includes/plugin.php');
}
return get_plugin_data($this->pluginAbsolutePath, false, false);
}

public function removeHooks() {
remove_filter('upgrader_post_install', array($this, 'clearCachedVersion'));
remove_action('delete_site_transient_update_plugins', array($this, 'clearCachedVersion'));
}

/**
* Check if the plugin file is inside the mu-plugins directory.
*
* @return bool
*/
public function isMuPlugin() {
static $cachedResult = null;

if ( $cachedResult === null ) {
//Convert both paths to the canonical form before comparison.
$muPluginDir = realpath(WPMU_PLUGIN_DIR);
$pluginPath = realpath($this->pluginAbsolutePath);

$cachedResult = (strpos($pluginPath, $muPluginDir) === 0);
}

return $cachedResult;
}
}

endif;
2 changes: 1 addition & 1 deletion Puc/v4p4/Plugin/Ui.php
Expand Up @@ -198,7 +198,7 @@ public function handleManualCheck() {
public function displayManualCheckResult() {
if ( isset($_GET['puc_update_check_result'], $_GET['puc_slug']) && ($_GET['puc_slug'] == $this->updateChecker->slug) ) {
$status = strval($_GET['puc_update_check_result']);
$title = $this->updateChecker->getPluginTitle();
$title = $this->updateChecker->getInstalledPackage()->getPluginTitle();
$noticeClass = 'updated notice-success';
$details = '';

Expand Down

0 comments on commit 4f6afa9

Please sign in to comment.