Skip to content

Commit

Permalink
* Fix for non-image uploads when you have the WordPress setting "" tu…
Browse files Browse the repository at this point in the history
…rned off but no upload path set in Cloud Storage Settings. If you were having problems with videos, PDF's, etc. this should fix it.

* Performance fix for sites with huge post tables that were seeing slow page performance.
* Fix for IPTC parsing that contains binary data
* Fix for a library conflict
* Warning that the built-in Dynamic Images functionality will be deprecated in the next major version
* Warning about library incompatibility with TranslatePress
  • Loading branch information
jawngee committed Feb 19, 2020
1 parent 4baa215 commit 311931f
Show file tree
Hide file tree
Showing 140 changed files with 10,194 additions and 1,308 deletions.
10 changes: 10 additions & 0 deletions classes/Storage/StorageGlobals.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ final class StorageGlobals {
/** @var bool */
private $deleteFromStorage = false;

/** @var bool */
private $cacheLookups = true;

/** @var array */
private $alternateFormatTypes = ['image/pdf', 'application/pdf', 'image/psd', 'application/vnd.adobe.illustrator'];

Expand Down Expand Up @@ -120,6 +123,8 @@ private function __construct() {
$this->privacyVideo = Environment::Option('mcloud-storage-privacy-video', null, "inherit");
$this->privacyDocs = Environment::Option('mcloud-storage-privacy-docs', null, "inherit");

$this->cacheLookups = Environment::Option('mcloud-storage-cache-lookups', null, true);

$ignored = Environment::Option('mcloud-storage-ignored-mime-types', null, '');
$ignored_lines = explode("\n", $ignored);
if(count($ignored_lines) <= 1) {
Expand Down Expand Up @@ -354,6 +359,11 @@ public static function deleteFromStorage() {
return self::instance()->deleteFromStorage;
}

/** @return bool */
public static function cacheLookups() {
return self::instance()->cacheLookups;
}

/**
* @return array
*/
Expand Down
148 changes: 148 additions & 0 deletions classes/Storage/StoragePostMap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php

// Copyright (c) 2016 Interfacelab LLC. All rights reserved.
//
// Released under the GPLv3 license
// http://www.gnu.org/licenses/gpl-3.0.html
//
// **********************************************************************
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// **********************************************************************

namespace ILAB\MediaCloud\Storage;

/**
* Interface for creating the required tables
*/
final class StoragePostMap {
const DB_VERSION = '1.0.0';
const DB_KEY = 'mcloud_post_map_db_version';

private static $installed = false;
private static $cache = [];

/**
* Insures the additional database tables are installed
*/
public static function init() {
static::verifyInstalled();
}

//region Install Database Tables

protected static function verifyInstalled() {
if (static::$installed === true) {
return true;
}

$currentVersion = get_site_option(self::DB_KEY);
if (!empty($currentVersion) && version_compare(self::DB_VERSION, $currentVersion, '==')) {
global $wpdb;

$tableName = $wpdb->base_prefix.'mcloud_post_map';
$exists = ($wpdb->get_var("SHOW TABLES LIKE '$tableName'") == $tableName);
if ($exists) {
static::$installed = true;
return true;
}
}

return static::installMapTable();
}

protected static function installMapTable() {
global $wpdb;

$tableName = $wpdb->base_prefix.'mcloud_post_map';
$charset = $wpdb->get_charset_collate();

$sql = "CREATE TABLE {$tableName} (
id BIGINT AUTO_INCREMENT,
post_id BIGINT NOT NULL,
post_url VARCHAR(255) NOT NULL,
PRIMARY KEY (id),
KEY post_id(post_id),
KEY post_url(post_url(255))
) {$charset};";

require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);

$exists = ($wpdb->get_var("SHOW TABLES LIKE '$tableName'") == $tableName);
if ($exists) {
update_site_option(self::DB_KEY, self::DB_VERSION);
static::$installed = true;
return true;
}

static::$installed = false;
return false;
}

//endregion

//region Queries
public static function uncachedAttachmentIdFromURL($url, $bucketName) {
global $wpdb;

$query = $wpdb->prepare("select ID from {$wpdb->posts} where post_type='attachment' and guid = %s order by ID desc limit 1", $url);
$postId = $wpdb->get_var($query);

if (empty($postId)) {
$parsedUrl = parse_url($url);
$path = ltrim($parsedUrl['path'], '/');

if (!empty($bucketName) && (strpos($path, $bucketName) === 0)) {
$path = ltrim(str_replace($bucketName,'', $path),'/');
}

$path = apply_filters('media-cloud/glide/clean-path', $path);

$query = $wpdb->prepare("select ID from {$wpdb->posts} where post_type='attachment' and guid like %s order by ID desc limit 1", '%'.$path);
$postId = $wpdb->get_var($query);
}

return $postId;
}

public static function attachmentIdFromURL($postId, $url, $bucketName) {
if (!empty($postId)) {
return $postId;
}

if (isset(static::$cache[$url])) {
return static::$cache[$url];
}

if (!empty(StorageGlobals::cacheLookups())) {
global $wpdb;

$tableName = $wpdb->base_prefix.'mcloud_post_map';

if (static::verifyInstalled()) {
$query = $wpdb->prepare("select post_id from {$tableName} where post_url = %s order by post_id desc limit 1", $url);
$postId = (int)$wpdb->get_var($query);
if (($postId === -1) || !empty($postId)) {
return ($postId === -1) ? null : $postId;
}
}

$postId = static::uncachedAttachmentIdFromURL($url, $bucketName);

if (!empty($postId)) {
static::$cache[$url] = $postId;
if (static::$installed === true) {
$wpdb->insert($tableName, ['post_id' => empty($postId) ? -1 : $postId, 'post_url' => $url], ['%d', '%s']);
}
}

return $postId;
}

$postId = static::uncachedAttachmentIdFromURL($url, $bucketName);
return $postId;
}
//endregion
}
38 changes: 25 additions & 13 deletions classes/Tools/Storage/StorageTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use ILAB\MediaCloud\Storage\StorageInterface ;
use ILAB\MediaCloud\Storage\StorageManager ;
use ILAB\MediaCloud\Storage\StorageGlobals ;
use ILAB\MediaCloud\Storage\StoragePostMap ;
use ILAB\MediaCloud\Tasks\TaskManager ;
use ILAB\MediaCloud\Tasks\TaskSchedule ;
use ILAB\MediaCloud\Tools\Storage\Tasks\CleanUploadsTask ;
Expand Down Expand Up @@ -251,6 +252,21 @@ public function setup()
TaskManager::registerTask( UnlinkTask::class );

if ( $this->enabled() ) {
if ( is_admin() ) {

if ( empty(get_option( 'uploads_use_yearmonth_folders' )) && empty(StorageGlobals::prefixFormat()) ) {
$mediaUrl = ilab_admin_url( 'options-media.php' );
$settingsUrl = ilab_admin_url( 'admin.php?page=media-cloud-settings-storage#upload-handling' );
NoticeManager::instance()->displayAdminNotice(
'warning',
"You have the WordPress setting <a href='{$mediaUrl}'><strong>Organize my uploads into month and year based folders</strong></a> disabled, but haven't specified an <em>Upload Path</em> in <a href='{$settingsUrl}'>Cloud Storage Settings</a>. It is recommended that you either enable that setting, or set an upload directory. We recommend setting the <em>Upload Path</em> to <code>@{date:Y/m}</code>.",
true,
'mcloud-no-upload-path',
365
);
}

}
TaskManager::registerTask( CleanUploadsTask::class );
TaskManager::registerTask( DeleteUploadsTask::class );
foreach ( $this->toolInfo['compatibleImageOptimizers'] as $key => $plugin ) {
Expand Down Expand Up @@ -1267,6 +1283,9 @@ private function fixOffloadS3Meta( $postId, $meta )
public function addAttachment( $post_id )
{
$file = get_post_meta( $post_id, '_wp_attached_file', true );
if ( !isset( $this->uploadedDocs[$file] ) ) {
$file = '/' . $file;
}

if ( isset( $this->uploadedDocs[$file] ) ) {
add_post_meta( $post_id, 'ilab_s3_info', $this->uploadedDocs[$file] );
Expand All @@ -1276,6 +1295,11 @@ public function addAttachment( $post_id )
$file,
$this->uploadedDocs[$file]
);
} else {
Logger::info( "addAttachment - Missing '{$file}' key on uploadeDocs." );
$keys = array_keys( $this->uploadedDocs );
$keyList = implode( ' , ', $keys );
Logger::info( 'addAttachment - Have keys: ' . $keyList );
}

}
Expand Down Expand Up @@ -2588,19 +2612,7 @@ private function replaceImageInContent( $id, $data, $content )

public function attachmentIdFromURL( $postId, $url )
{
if ( !empty($postId) ) {
return $postId;
}
global $wpdb ;
$parsedUrl = parse_url( $url );
$path = ltrim( $parsedUrl['path'], '/' );
if ( strpos( $path, $this->client()->bucket() ) === 0 ) {
$path = ltrim( str_replace( $this->client()->bucket(), '', $path ), '/' );
}
$path = apply_filters( 'media-cloud/glide/clean-path', $path );
$query = $wpdb->prepare( "select ID from {$wpdb->posts} where post_type='attachment' and guid like %s order by ID desc limit 1", '%' . $path );
$postId = $wpdb->get_var( $query );
return $postId;
return StoragePostMap::attachmentIdFromURL( $postId, $url, $this->client()->bucket() );
}

//endregion
Expand Down
55 changes: 55 additions & 0 deletions classes/Utilities/Misc/Symfony/Component/Config/ConfigCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ILAB\MediaCloud\Utilities\Misc\Symfony\Component\Config;

use ILAB\MediaCloud\Utilities\Misc\Symfony\Component\Config\Resource\SelfCheckingResourceChecker;
/**
* ConfigCache caches arbitrary content in files on disk.
*
* When in debug mode, those metadata resources that implement
* \Symfony\Component\Config\Resource\SelfCheckingResourceInterface will
* be used to check cache freshness.
*
* @author Fabien Potencier <[email protected]>
* @author Matthias Pigulla <[email protected]>
*/
class ConfigCache extends \ILAB\MediaCloud\Utilities\Misc\Symfony\Component\Config\ResourceCheckerConfigCache
{
private $debug;
/**
* @param string $file The absolute cache path
* @param bool $debug Whether debugging is enabled or not
*/
public function __construct($file, $debug)
{
$this->debug = (bool) $debug;
$checkers = [];
if (\true === $this->debug) {
$checkers = [new \ILAB\MediaCloud\Utilities\Misc\Symfony\Component\Config\Resource\SelfCheckingResourceChecker()];
}
parent::__construct($file, $checkers);
}
/**
* Checks if the cache is still fresh.
*
* This implementation always returns true when debug is off and the
* cache file exists.
*
* @return bool true if the cache is fresh, false otherwise
*/
public function isFresh()
{
if (!$this->debug && \is_file($this->getPath())) {
return \true;
}
return parent::isFresh();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ILAB\MediaCloud\Utilities\Misc\Symfony\Component\Config;

/**
* Basic implementation of ConfigCacheFactoryInterface that
* creates an instance of the default ConfigCache.
*
* This factory and/or cache <em>do not</em> support cache validation
* by means of ResourceChecker instances (that is, service-based).
*
* @author Matthias Pigulla <[email protected]>
*/
class ConfigCacheFactory implements \ILAB\MediaCloud\Utilities\Misc\Symfony\Component\Config\ConfigCacheFactoryInterface
{
private $debug;
/**
* @param bool $debug The debug flag to pass to ConfigCache
*/
public function __construct($debug)
{
$this->debug = $debug;
}
/**
* {@inheritdoc}
*/
public function cache($file, $callback)
{
if (!\is_callable($callback)) {
throw new \InvalidArgumentException(\sprintf('Invalid type for callback argument. Expected callable, but got "%s".', \gettype($callback)));
}
$cache = new \ILAB\MediaCloud\Utilities\Misc\Symfony\Component\Config\ConfigCache($file, $this->debug);
if (!$cache->isFresh()) {
\call_user_func($callback, $cache);
}
return $cache;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ILAB\MediaCloud\Utilities\Misc\Symfony\Component\Config;

/**
* Interface for a ConfigCache factory. This factory creates
* an instance of ConfigCacheInterface and initializes the
* cache if necessary.
*
* @author Matthias Pigulla <[email protected]>
*/
interface ConfigCacheFactoryInterface
{
/**
* Creates a cache instance and (re-)initializes it if necessary.
*
* @param string $file The absolute cache file path
* @param callable $callable The callable to be executed when the cache needs to be filled (i. e. is not fresh). The cache will be passed as the only parameter to this callback
*
* @return ConfigCacheInterface The cache instance
*/
public function cache($file, $callable);
}
Loading

0 comments on commit 311931f

Please sign in to comment.