Permalink
Browse files

Initial implementation.

  • Loading branch information...
1 parent 3109c06 commit c3174b69640a3ccd4ceffdc7934fefb3fb5aa34f @YahnisElsts committed Mar 4, 2013
Showing with 412 additions and 0 deletions.
  1. +2 −0 cache/.htaccess
  2. +2 −0 includes/.htaccess
  3. +54 −0 includes/Wpup/FileCache.php
  4. +145 −0 includes/Wpup/Package.php
  5. +18 −0 includes/Wpup/Request.php
  6. +178 −0 includes/Wpup/UpdateServer.php
  7. +4 −0 index.php
  8. +7 −0 loader.php
  9. +2 −0 packages/.htaccess
View
@@ -0,0 +1,2 @@
+Order deny,allow
+Deny from all
View
@@ -0,0 +1,2 @@
+Order deny,allow
+Deny from all
@@ -0,0 +1,54 @@
+<?php
+/**
+ * A basic file-based cache.
+ */
+class Wpup_FileCache {
+ protected $cacheDirectory;
+
+ public function __construct($cacheDirectory) {
+ $this->cacheDirectory = $cacheDirectory;
+ }
+
+ /**
+ * Get cached value.
+ *
+ * @param string $key
+ * @return mixed|null
+ */
+ public function get($key) {
+ $filename = $this->getCacheFilename($key);
+ if ( is_file($filename) && is_readable($filename) ) {
+ $cache = unserialize(file_get_contents($filename));
+ if ( $cache['expiration_time'] < time() ) {
+ return null; //Cache expired.
+ } else {
+ return $cache['value'];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Update the cache.
+ *
+ * @param string $key Cache key.
+ * @param mixed $value The value to store in the cache.
+ * @param int $expiration Time until expiration, in seconds. Optional.
+ * @return void
+ */
+ public function set($key, $value, $expiration = 0) {
+ $cache = array(
+ 'expiration_time' => time() + $expiration,
+ 'value' => $value,
+ );
+ file_put_contents($this->getCacheFilename($key), serialize($cache));
+ }
+
+ /**
+ * @param string $key
+ * @return string
+ */
+ protected function getCacheFilename($key) {
+ return $this->cacheDirectory . '/' . $key . '.txt';
+ }
+}
@@ -0,0 +1,145 @@
+<?php
+class Wpup_Package {
+ /** @var string */
+ protected $filename;
+
+ /** @var array */
+ protected $metadata = array();
+
+ /** @var Wpup_FileCache */
+ protected $cache;
+
+ /** @var string */
+ public $slug;
+
+ public function __construct($slug, $filename = null, $metadata = array()) {
+ $this->slug = $slug;
+ $this->filename = $filename;
+ $this->metadata = $metadata;
+ }
+
+ public function getFilename() {
+ return $this->filename;
+ }
+
+ public function getMetadata() {
+ return array_merge($this->metadata, array('slug' => $this->slug));
+ }
+
+ /**
+ * Load package information from a Zip archive.
+ *
+ * We'll try to load processed metadata from the cache first (if available), and if that
+ * fails we'll extract plugin/theme details from the ZIP file itself.
+ *
+ * @param string $filename
+ * @param string $slug
+ * @param Wpup_FileCache $cache
+ * @return Wpup_Package
+ */
+ public static function fromArchive($filename, $slug = null, Wpup_FileCache $cache = null) {
+ $modified = filemtime($filename);
+ $cacheKey = 'metadata-' . md5($filename . '|' . filesize($filename) . '|' . $modified);
+ $metadata = null;
+
+ //Try the cache first.
+ if ( isset($cache) ) {
+ $metadata = $cache->get($cacheKey);
+ }
+
+ if ( !isset($metadata) || !is_array($metadata) ) {
+ $metadata = self::extractMetadata($filename);
+ $metadata['last_updated'] = gmdate('Y-m-d H:i:s', $modified);
+ }
+
+ //Update cache.
+ if ( isset($cache) ) {
+ $cache->set($cacheKey, $metadata, 7 * 24 * 3600);
+ }
+ if ( $slug === null ) {
+ $slug = $metadata['slug'];
+ }
+
+ return new self($slug, $filename, $metadata);
+ }
+
+ /**
+ * Extract plugin or theme headers and readme contents from a 's ZIP file and convert them
+ * into a structure compatible with the custom update checker.
+ *
+ * See this page for an overview of the plugin metadata format:
+ * @link https://spreadsheets.google.com/pub?key=0AqP80E74YcUWdEdETXZLcXhjd2w0cHMwX2U1eDlWTHc&authkey=CK7h9toK&hl=en&single=true&gid=0&output=html
+ *
+ * @param string $zipFilename
+ * @return array
+ */
+ public static function extractMetadata($zipFilename){
+ $packageInfo = WshWordPressPackageParser::parsePackage($zipFilename, true);
+ $meta = array();
+
+ if ( isset($packageInfo['header']) && !empty($packageInfo['header']) ){
+ $mapping = array(
+ 'Name' => 'name',
+ 'Version' => 'version',
+ 'PluginURI' => 'homepage',
+ 'ThemeURI' => 'homepage',
+ 'Author' => 'author',
+ 'AuthorURI' => 'author_homepage',
+ 'DetailsURI' => 'details_url', //Only for themes.
+ );
+ foreach($mapping as $headerField => $metaField){
+ if ( array_key_exists($headerField, $packageInfo['header']) && !empty($packageInfo['header'][$headerField]) ){
+ $meta[$metaField] = $packageInfo['header'][$headerField];
+ }
+ }
+
+ //Theme metadata should include a "details_url" that specifies the page to display
+ //when the user clicks "View version x.y.z details". If the developer didn't provide
+ //it by setting the "Details URI" header, we'll default to the theme homepage ("Theme URI").
+ if ( $packageInfo['type'] === 'theme' && !isset($meta['details_url']) && isset($meta['homepage']) ) {
+ $meta['details_url'] = $meta['homepage'];
+ }
+ }
+
+ if ( !empty($packageInfo['readme']) ){
+ $mapping = array('requires', 'tested');
+ foreach($mapping as $readmeField){
+ if ( !empty($packageInfo['readme'][$readmeField]) ){
+ $meta[$readmeField] = $packageInfo['readme'][$readmeField];
+ }
+ }
+ if ( !empty($packageInfo['readme']['sections']) && is_array($packageInfo['readme']['sections']) ){
+ foreach($packageInfo['readme']['sections'] as $sectionName => $sectionContent){
+ $sectionName = str_replace(' ', '_', strtolower($sectionName));
+ $meta['sections'][$sectionName] = $sectionContent;
+ }
+ }
+
+ //Check if we have an upgrade notice for this version
+ if ( isset($meta['sections']['upgrade_notice']) && isset($meta['version']) ){
+ $regex = "@<h4>\s*" . preg_quote($meta['version']) . "\s*</h4>[^<>]*?<p>(.+?)</p>@i";
+ if ( preg_match($regex, $meta['sections']['upgrade_notice'], $matches) ){
+ $meta['upgrade_notice'] = trim(strip_tags($matches[1]));
+ }
+ }
+ }
+
+ if ( !isset($meta['last_updated']) ) {
+ $meta['last_updated'] = gmdate('Y-m-d H:i:s', filemtime($zipFilename));
+ }
+
+ $mainFile = $packageInfo['type'] === 'plugin' ? $packageInfo['pluginFile'] : $packageInfo['stylesheet'];
+ $meta['slug'] = basename(dirname(strtolower($mainFile)));
+ //Idea: Warn the user if the package doesn't match the expected "/slug/other-files" layout.
+
+ return $meta;
+ }
+
+ public function getFileSize() {
+ return filesize($this->filename);
+ }
+
+ public function getLastModified() {
+ return filemtime($this->filename);
+ }
+}
@@ -0,0 +1,18 @@
+<?php
+class Wpup_Request {
+ /** @var array */
+ public $query = array();
+ /** @var string */
+ public $action;
+ /** @var string */
+ public $slug;
+ /** @var Wpup_Package */
+ public $package;
+
+ public function __construct($query, $action, $slug = null, $package = null) {
+ $this->query = $query;
+ $this->action = $action;
+ $this->slug = $slug;
+ $this->package = $package;
+ }
+}
Oops, something went wrong.

0 comments on commit c3174b6

Please sign in to comment.