Initial commit
This commit is contained in:
37
src/Actions/Convert.php
Normal file
37
src/Actions/Convert.php
Normal 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);
|
||||
}
|
||||
}
|
33
src/Actions/Convert/Attachment.php
Normal file
33
src/Actions/Convert/Attachment.php
Normal 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"') . '%',
|
||||
]
|
||||
)));
|
||||
}
|
||||
}
|
115
src/Actions/Convert/Replacer/PostAttachmentReplacer.php
Normal file
115
src/Actions/Convert/Replacer/PostAttachmentReplacer.php
Normal 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;
|
||||
}
|
||||
}
|
100
src/Actions/Convert/ReplacerService.php
Normal file
100
src/Actions/Convert/ReplacerService.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
6
src/Exceptions/LoggerException.php
Normal file
6
src/Exceptions/LoggerException.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php namespace WpsMcloud\Exceptions;
|
||||
|
||||
class LoggerException extends WpstudioMediaCloudTransformException
|
||||
{
|
||||
|
||||
}
|
6
src/Exceptions/ViewNotFoundException.php
Normal file
6
src/Exceptions/ViewNotFoundException.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php namespace WpsMcloud\Exceptions;
|
||||
|
||||
class ViewNotFoundException extends WpstudioMediaCloudTransformException
|
||||
{
|
||||
|
||||
}
|
6
src/Exceptions/WpstudioMediaCloudTransformException.php
Normal file
6
src/Exceptions/WpstudioMediaCloudTransformException.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php namespace WpsMcloud\Exceptions;
|
||||
|
||||
abstract class WpstudioMediaCloudTransformException extends \Exception
|
||||
{
|
||||
|
||||
}
|
81
src/Logger.php
Normal file
81
src/Logger.php
Normal 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>';
|
||||
}
|
||||
}
|
68
src/Models/PostAttachment.php
Normal file
68
src/Models/PostAttachment.php
Normal 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
6
src/Pages/Converter.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php namespace WpsMcloud\Pages;
|
||||
|
||||
class Converter extends Page
|
||||
{
|
||||
|
||||
}
|
55
src/Pages/Page.php
Normal file
55
src/Pages/Page.php
Normal 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
10
src/Support/Counters.php
Normal 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
46
src/Support/Http.php
Normal 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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user