Initial commit

This commit is contained in:
2022-07-10 10:27:25 +03:00
commit e3e7af347b
22 changed files with 1618 additions and 0 deletions

37
src/Actions/Convert.php Normal file
View File

@ -0,0 +1,37 @@
<?php namespace WpsMcloud\Actions;
use WpsMcloud\Actions\Convert\Attachment;
use WpsMcloud\Actions\Convert\ReplacerService;
use WpsMcloud\Support\Counters;
class Convert
{
private Attachment $attachment;
private ReplacerService $replacer;
public static int $countProcessedImages = 0;
public static int $countImagesNotFound = 0;
public function __construct()
{
$this->attachment = new Attachment();
$this->replacer = new ReplacerService();
}
public function run()
{
$images = $this->attachment->getImagesWithoutS3MetaData();
echo sprintf('Count for the processing: %d<br>', count($images));
foreach ($images as $post) {
$this->replacer->processImage($post);
}
echo sprintf('Processed: %d<br>', Counters::$processedImages);
echo sprintf('Not found: %d<br>', Counters::$imagesNotFound);
}
}

View File

@ -0,0 +1,33 @@
<?php namespace WpsMcloud\Actions\Convert;
use WpsMcloud\Models\PostAttachment;
class Attachment
{
public function getImagesWithoutS3MetaData(): array
{
global $wpdb;
$query = <<<EOF
SELECT $wpdb->posts.ID, $wpdb->posts.guid, $wpdb->posts.post_mime_type, $wpdb->postmeta.meta_id, $wpdb->postmeta.meta_value
FROM $wpdb->posts
JOIN $wpdb->postmeta ON $wpdb->posts.ID=$wpdb->postmeta.post_id
LEFT JOIN $wpdb->postmeta pm2 ON $wpdb->posts.ID=pm2.post_id AND pm2.meta_key = %s
WHERE
$wpdb->posts.post_type = %s and
$wpdb->postmeta.meta_key = %s and
$wpdb->postmeta.meta_value not like %s and
pm2.meta_id IS NULL
EOF;
return PostAttachment::get($wpdb->get_results($wpdb->prepare(
$query,
[
PostAttachment::META_KEY_FLAGGED_AS_404,
'attachment',
'_wp_attachment_metadata',
'%' . $wpdb->esc_like('"s3"') . '%',
]
)));
}
}

View File

@ -0,0 +1,115 @@
<?php namespace WpsMcloud\Actions\Convert\Replacer;
use WpsMcloud\Actions\Convert\ReplacerService;
use WpsMcloud\Models\PostAttachment;
class PostAttachmentReplacer
{
private PostAttachment $post;
private ReplacerService $replacer;
public string $mcloudPostUrl;
public string $mcloudPostBaseUrl;
public string $localPostBaseUrl;
/**
* @var string
* @desc Filename with prepend parts after "wp-content/uploads/"
*/
public string $key;
/**
* @var string Only prepends parts without filename
*/
public string $baseKey;
public function __construct(PostAttachment $post, ReplacerService $replacer)
{
$this->post = $post;
$this->replacer = $replacer;
$this->mcloudPostUrl = str_replace(
$replacer->getUploadsDirBaseUrl(),
$replacer->getMcloudBaseUrl(),
$post->getUrl()
);
$this->mcloudPostBaseUrl = trailingslashit(
str_replace($this->post->getBasename(), '', $this->mcloudPostUrl)
);
$this->localPostBaseUrl = trailingslashit(
str_replace($this->post->getBasename(), '', $this->post->getUrl())
);
$this->key = ltrim(
str_replace($replacer->getMcloudBaseUrl(), '', $this->mcloudPostUrl),
'/',
);
$this->baseKey = ltrim(
trailingslashit(
str_replace(
$this->post->getBasename(),
'',
$this->key
)
),
'/'
);
}
public function getGeneralS3Info(): array
{
return $this->getS3Info($this->getMcloudPostUrl(), $this->getKey());
}
public function getSizeS3Info(string $sizeFilename): array
{
return $this->getS3Info(
$this->getMcloudPostBaseUrl() . $sizeFilename,
$this->getBaseKey() . $sizeFilename
);
}
private function getS3Info(string $url, string $key): array
{
return [
'url' => $url,
'bucket' => $this->replacer->getBucket(),
'provider' => 's3',
'privacy' => ReplacerService::S3_ACL,
'v' => MEDIA_CLOUD_INFO_VERSION,
'key' => $key,
'options' => [],
'mime-type' => $this->post->getPostMimeType(),
];
}
public function getMcloudPostUrl(): string
{
return $this->mcloudPostUrl;
}
public function getMcloudPostBaseUrl(): string
{
return $this->mcloudPostBaseUrl;
}
public function getLocalPostBaseUrl(): string
{
return $this->localPostBaseUrl;
}
public function getKey(): string
{
return $this->key;
}
public function getBaseKey(): string
{
return $this->baseKey;
}
}

View File

@ -0,0 +1,100 @@
<?php namespace WpsMcloud\Actions\Convert;
use WpsMcloud\Actions\Convert;
use WpsMcloud\Models\PostAttachment;
use WpsMcloud\Support\Counters;
use WpsMcloud\Support\Http;
class ReplacerService
{
const S3_ACL = 'public-read';
private string $uploadsDirBaseUrl;
private string $mcloudEndPoint;
private string $bucket;
private string $mcloudBaseUrl;
public function __construct()
{
$this->uploadsDirBaseUrl = trailingslashit(wp_get_upload_dir()['baseurl']);
$this->mcloudEndPoint = trailingslashit(get_option('mcloud-storage-s3-endpoint'));
$this->bucket = get_option('mcloud-storage-s3-bucket');
$this->mcloudBaseUrl = trailingslashit( $this->getMcloudEndPoint() . $this->bucket);
}
public function processImage(PostAttachment $post): void
{
if (!Http::fileExists($post->getUrl())) {
$post->setFlaggedAs404();
echo sprintf('Not found image %d: %s', $post->getId(), $post->getUrl());
Counters::$imagesNotFound++;
return;
}
$postAttachmentReplacer = new Convert\Replacer\PostAttachmentReplacer($post, $this);
$meta = $post->getMeta();
$meta['file'] = $postAttachmentReplacer->getKey();
$meta['s3'] = $postAttachmentReplacer->getGeneralS3Info();
if (array_key_exists('sizes', $meta) && is_array($meta['sizes'])) {
$newSizes = [];
foreach ($meta['sizes'] as $size => $sizeData) {
$sizeFilename = $sizeData['file'];
$localSizeUrl = $postAttachmentReplacer->getLocalPostBaseUrl() . $sizeFilename;
if (!Http::fileExists($localSizeUrl)) {
echo sprintf(
'Not found size "%s" image %d: %s',
$sizeFilename,
$post->getId(),
$localSizeUrl
) . PHP_EOL;
Counters::$imagesNotFound++;
continue;
}
$sizeData['s3'] = $postAttachmentReplacer->getSizeS3Info($sizeFilename);
$newSizes[$size] = $sizeData;
}
$meta['sizes'] = $newSizes;
}
update_post_meta( $post->getId(), '_wp_attachment_metadata', $meta );
Counters::$processedImages++;
}
public function getUploadsDirBaseUrl(): string
{
return $this->uploadsDirBaseUrl;
}
public function getMcloudEndPoint(): string
{
return $this->mcloudEndPoint;
}
public function getBucket(): string
{
return $this->bucket;
}
public function getMcloudBaseUrl(): string
{
return $this->mcloudBaseUrl;
}
}

View File

@ -0,0 +1,6 @@
<?php namespace WpsMcloud\Exceptions;
class LoggerException extends WpstudioMediaCloudTransformException
{
}

View File

@ -0,0 +1,6 @@
<?php namespace WpsMcloud\Exceptions;
class ViewNotFoundException extends WpstudioMediaCloudTransformException
{
}

View File

@ -0,0 +1,6 @@
<?php namespace WpsMcloud\Exceptions;
abstract class WpstudioMediaCloudTransformException extends \Exception
{
}

81
src/Logger.php Normal file
View File

@ -0,0 +1,81 @@
<?php namespace WpsMcloud;
use WpsMcloud\Exceptions\LoggerException;
class Logger
{
const LOG_TYPE_HTML = 'html';
const LOG_TYPE_ERROR_LOG = 'error_log';
const LOG_TYPE_BOTH = 'both';
private static array $logTypes = [
self::LOG_TYPE_HTML,
self::LOG_TYPE_ERROR_LOG,
self::LOG_TYPE_BOTH,
];
private string $logType;
/**
* @param string $logType
* @throws LoggerException
*/
public function __construct(string $logType)
{
$this->validateLogType($logType);
$this->logType = $logType;
}
/**
* @param string $logType
* @throws LoggerException
*/
private function validateLogType(string $logType): void
{
if (!in_array($logType, self::$logTypes)) {
throw new LoggerException('Log type wrong: ' . $logType);
}
}
public function log(string $message, bool $newLineAfter = true): void
{
switch ($this->logType) {
case self::LOG_TYPE_HTML:
$this->outputToDefaultStream($message, $newLineAfter);
break;
case self::LOG_TYPE_ERROR_LOG:
$this->outputToPhpErrorLog($message);
break;
case self::LOG_TYPE_BOTH:
$this->outputToDefaultStream($message, $newLineAfter);
$this->outputToPhpErrorLog($message);
break;
}
}
private function outputToDefaultStream(string $message, bool $newLineAfter): void
{
echo $message;
if ($newLineAfter) {
echo PHP_EOL;
}
}
private function outputToPhpErrorLog(string $message): void
{
error_log($message);
}
public function openPreformating()
{
echo '<pre>';
}
public function closePreformating()
{
echo '</pre>';
}
}

View File

@ -0,0 +1,68 @@
<?php namespace WpsMcloud\Models;
use JetBrains\PhpStorm\Pure;
class PostAttachment
{
const META_KEY_FLAGGED_AS_404 = '_wp_media_cloud_transform_404';
const META_KEY_ATTACHMENT_METADATA = '_wp_attachment_metadata';
public int $id;
public string $meta_value;
public ?array $meta;
public string $guid;
public string $post_mime_type;
public function __construct($post)
{
$this->id = $post->ID;
$this->meta_value = $post->meta_value;
$this->guid = $post->guid;
$this->post_mime_type = $post->post_mime_type;
}
public static function get(array $posts): array
{
return array_map(fn ($post) => new self($post), $posts);
}
public function getId(): string
{
return $this->id;
}
public function getMeta(): array
{
if (!isset($this->meta)) {
$this->meta = unserialize($this->meta_value);
}
return $this->meta;
}
public function getUrl(): string
{
return $this->guid;
}
public function getBasename(): string
{
return basename($this->getUrl());
}
public function getPostMimeType(): string
{
return $this->post_mime_type;
}
public function setAttachmentMetaData(array $meta)
{
update_post_meta($this->getId(), self::META_KEY_ATTACHMENT_METADATA, $meta);
}
public function setFlaggedAs404()
{
add_post_meta($this->getId(), self::META_KEY_FLAGGED_AS_404, 1);
}
}

6
src/Pages/Converter.php Normal file
View File

@ -0,0 +1,6 @@
<?php namespace WpsMcloud\Pages;
class Converter extends Page
{
}

55
src/Pages/Page.php Normal file
View File

@ -0,0 +1,55 @@
<?php namespace WpsMcloud\Pages;
use WpsMcloud\Exceptions\ViewNotFoundException;
abstract class Page
{
private static string $viewsDir = 'views';
/**
* @throws ViewNotFoundException
*/
public function render(): void
{
$this->renderView();
}
/**
* @throws ViewNotFoundException
*/
private function renderView(): void
{
$lowerCaseLastPartThisClassName = strtolower(array_reverse(explode('\\', get_class($this)))[0]);
$filePathWithoutExtension = self::getViewsPath() . DIRECTORY_SEPARATOR .$lowerCaseLastPartThisClassName;
$allowedExtensions = [
'html',
'php'
];
$fileIsFound = false;
while (!$fileIsFound && $currentExtension = current($allowedExtensions)) {
if (file_exists($filePath = $filePathWithoutExtension . '.' . $currentExtension)) {
$fileIsFound = true;
include $filePath;
}
}
if (!$fileIsFound) {
throw new ViewNotFoundException(sprintf(
'Not found any view file in view dir "%s" for this controller "%s" with these available extension: %s',
self::getViewsPath(),
$lowerCaseLastPartThisClassName,
implode(', ', $allowedExtensions)
));
}
}
private static function getViewsPath(): string
{
return WPSTUDIO_MEDIA_CLOUD_TRANFORM_BASE_PATH . DIRECTORY_SEPARATOR . self::$viewsDir;
}
}

10
src/Support/Counters.php Normal file
View File

@ -0,0 +1,10 @@
<?php namespace WpsMcloud\Support;
class Counters
{
/**
* @desc Convert action
*/
public static $imagesNotFound = 0;
public static $processedImages = 0;
}

46
src/Support/Http.php Normal file
View File

@ -0,0 +1,46 @@
<?php namespace WpsMcloud\Support;
use Guzzle\Http\Client;
use Guzzle\Http\Exception\ClientErrorResponseException;
class Http
{
private static Client $guzzle;
private static function getGuzzle(): Client
{
if (!isset(static::$guzzle)) {
static::$guzzle = new Client();
}
return static::$guzzle;
}
public static function fileExists(string $url, ?\Closure $successCallback = null, ?\Closure $errorCallback = null): bool
{
try {
$res = self::getGuzzle()->createRequest('HEAD', $url, null, null, [
'allow_redirects' => true,
])->send();
if ($res->getStatusCode() == 200) {
if ($successCallback !== null) {
$successCallback();
}
return true;
}
} catch (ClientErrorResponseException $e) {
if ($errorCallback !== null) {
throw $e;
}
}
if ($errorCallback !== null) {
$errorCallback();
}
return false;
}
}