Last active
August 11, 2023 04:20
-
-
Save sjardim/d74fae71b5bfe6a44ab88efc9aaa5279 to your computer and use it in GitHub Desktop.
'Synchronize all the page images uploaded through ProcessWire to a specified bucket in Amazon S3 and other places using Flysystem library.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php namespace ProcessWire; | |
use Aws\S3\S3Client; | |
use League\Flysystem\AwsS3v3\AwsS3Adapter; | |
use League\Flysystem\Filesystem; | |
use League\Flysystem\Adapter\Local; | |
class ProcessSync extends WireData implements Module, ConfigurableModule { | |
public static function getModuleInfo() { | |
return array( | |
'title' => 'Sync Images and Files with Flysystem Integration', | |
'summary' => 'Synchronize all the page images uploaded through ProcessWire to a specified bucket in Amazon S3 and other places using Flysystem library.', | |
'author' => 'Sérgio Jardim', | |
'href' => '', | |
'singular' => true, | |
'autoload' => true, | |
'icon' => 'amazon', | |
'version' => 001, | |
'requires' => array('ProcessWire>=3.0.80', 'PHP>=5.6') | |
); | |
} | |
/** | |
* Data as used by the get/set functions | |
* | |
*/ | |
protected $data = array(); | |
/** | |
* ------------------------------------------------------------------------ | |
* Default configuration values | |
* ------------------------------------------------------------------------ | |
* @return array | |
*/ | |
public static function getDefaultConfig() { | |
return array( | |
'AmazonS3Key' => '', | |
'AmazonS3Secret' => '', | |
'AmazonS3Region' => '', | |
'AmazonS3BucketName' => '', | |
'AmazonS3DirName' => '', | |
); | |
} | |
/** | |
* ------------------------------------------------------------------------ | |
* Populate default configuration (will be overwritten after constructor | |
* with user's own configuration) | |
* ------------------------------------------------------------------------ | |
* @return object | |
*/ | |
public function __construct() { | |
foreach(self::getDefaultConfig() as $key => $value) { | |
$this->$key = $value; | |
} | |
} | |
/** | |
* ------------------------------------------------------------------------ | |
* Build module configuration page | |
* ------------------------------------------------------------------------ | |
* @param array $data | |
* @return mixed | |
*/ | |
static public function getModuleConfigInputfields(array $data) { | |
$data = array_merge(self::getDefaultConfig(), $data); | |
// ------------------------------------------------------------------------ | |
// Build config screen form | |
// ------------------------------------------------------------------------ | |
$form = new InputfieldWrapper(); | |
// ------------------------------------------------------------------------ | |
// AmazonS3Key | |
// ------------------------------------------------------------------------ | |
$field = wire('modules')->get("InputfieldText"); | |
$field->name = "AmazonS3Key"; | |
$field->label = __("S3 User credential's key"); | |
$field->icon = "key"; | |
$field->columnWidth = '50'; | |
$field->value = $data['AmazonS3Key']; | |
$form->add($field); | |
// ------------------------------------------------------------------------ | |
// AmazonS3Secret | |
// ------------------------------------------------------------------------ | |
$field = wire('modules')->get("InputfieldText"); | |
$field->name = "AmazonS3Secret"; | |
$field->label = __("S3 User credential's secret"); | |
$field->icon = "book"; | |
$field->columnWidth = '50'; | |
$field->value = $data['AmazonS3Secret']; | |
$form->add($field); | |
// ------------------------------------------------------------------------ | |
// AmazonS3Region | |
// ------------------------------------------------------------------------ | |
$field = wire('modules')->get("InputfieldText"); | |
$field->name = "AmazonS3Region"; | |
$field->label = __("S3 Region"); | |
$field->icon = "globe"; | |
$field->columnWidth = '33'; | |
$field->notes = 'e.g.: "sa-east-1"'; | |
$field->value = $data['AmazonS3Region']; | |
$form->add($field); | |
// ------------------------------------------------------------------------ | |
// AmazonS3BucketName | |
// ------------------------------------------------------------------------ | |
$field = wire('modules')->get("InputfieldText"); | |
$field->name = "AmazonS3BucketName"; | |
$field->label = __("S3 Bucket Name"); | |
$field->icon = "inbox"; | |
$field->columnWidth = '33'; | |
$field->notes = 'e.g.: "website-name"'; | |
$field->value = $data['AmazonS3BucketName']; | |
$form->add($field); | |
// ------------------------------------------------------------------------ | |
// AmazonS3DirName | |
// ------------------------------------------------------------------------ | |
$field = wire('modules')->get("InputfieldText"); | |
$field->name = "AmazonS3DirName"; | |
$field->label = __("S3 Directory Name"); | |
$field->icon = "folder-open"; | |
$field->columnWidth = '33'; | |
$field->notes = 'e.g.: "images"'; | |
$field->value = $data['AmazonS3DirName']; | |
$form->add($field); | |
// ------------------------------------------------------------------------ | |
// Build form | |
// ------------------------------------------------------------------------ | |
return $form; | |
} | |
public function init() { | |
$this->client = S3Client::factory([ | |
'credentials' => [ | |
'key' => $this->AmazonS3Key, | |
'secret' => $this->AmazonS3Secret, | |
], | |
'region' => $this->AmazonS3Region, | |
'version' => 'latest', | |
]); | |
$this->bucket_name = $this->AmazonS3BucketName; | |
$this->dir_name = $this->AmazonS3DirName; | |
$this->s3_adapter = new AwsS3Adapter($this->client, $this->bucket_name, $this->dir_name); | |
$this->s3_filesystem = new Filesystem($this->s3_adapter); | |
// Fired when a file/image is added to a page in the admin | |
$this->addHookAfter('InputfieldFile::fileAdded', $this, 'uploadImageS3'); | |
if(!wire('config')->production) { | |
//Download images from server when their url is requested | |
//But on fire this hook when not in production by checking the production flag set in the config file | |
$this->addHookAfter('Pagefile::url, Pagefile::filename', $this, 'downloadImageServer'); | |
} | |
} | |
public function redirectImageURL($event){ | |
if($event->page->template == 'admin') return; | |
else | |
$event->return = | |
"https://" . | |
$this->AmazonS3BucketName . | |
".s3-" . | |
$this->AmazonS3Region . | |
".amazonaws.com/" . | |
$this->AmazonS3DirName . "/" . | |
$event->object->page . "/" . | |
$event->object->name; | |
} | |
// UPLOAD | |
/** | |
* Hook before InputfieldFile::fileAdded in auto mode | |
* Optimize image on upload | |
* | |
* @param HookEvent $event | |
* @return bool false if image extension is not in allowedExtensions | |
* | |
*/ | |
public function uploadImageS3($event){ | |
$file = $event->argumentsByName('pagefile'); | |
$filename = $file->name; | |
$pathToFile = $file->page . "/" . $filename; | |
$system_path = $file->filename(); | |
try{ | |
$file_on_s3 = $this->s3_filesystem->has($pathToFile); //check if file exists on AWS | |
if(!$file_on_s3) { | |
$contents = file_get_contents($system_path); | |
$this->s3_filesystem->put($pathToFile, $contents, array( | |
'visibility' => 'public', | |
)); //upload file with the same folder structure as in assets/files: page_id/file_name | |
if( wire('config')->debug ) wire('log')->save("process_sync", "Image uploaded to S3: {$system_path}"); | |
} | |
} | |
catch (Exception $e){ | |
throw new WireException("Error: Image not Added to S3: {$e->getMessage()}"); | |
} | |
} | |
/** | |
* This is called from AutoSmush module | |
* | |
* @param HookEvent $event | |
* | |
*/ | |
public function uploadImageVariationS3($AutoSmushImage){ | |
preg_match_all('/(\/site\/assets\/files\/)(\d+)(.+)/', $AutoSmushImage->url, $matches); | |
//(\d+) = #### | |
//(.+) = /IMAGENAME.400x0.jpg | |
$pathToFile = $matches[2][0].$matches[3][0]; | |
//.../public/site/assets/files/####/IMAGENAME.400x0.jpg" | |
$system_path = $AutoSmushImage->filename; | |
try{ | |
$contents = file_get_contents($system_path); | |
//Write or Update Files | |
$this->s3_filesystem->put($pathToFile, $contents, array( | |
'visibility' => 'public', | |
)); //upload file with the same folder structure as in assets/files: page_id/file_name | |
if( wire('config')->debug ) wire('log')->save("process_sync", "Image VARIATION uploaded to S3 (after AutoSmush): {$pathToFile}"); | |
} | |
catch (Exception $e){ | |
throw new WireException("Error: Image variation not Added to S3: {$e->getMessage()}"); | |
} | |
} | |
public function uploadExistingImages($file){ | |
$filename = $file->name; | |
$pathToFile = $file->page . "/" . $filename; | |
$system_path = $file->filename(); | |
try{ | |
$file_on_s3 = $this->s3_filesystem->has($pathToFile); //check if file exists on AWS | |
if(!$file_on_s3) { | |
$contents = file_get_contents($system_path); | |
$this->s3_filesystem->put($pathToFile, $contents, array( | |
'visibility' => 'public', | |
)); //upload file with the same folder structure as in assets/files: page_id/file_name | |
if( wire('config')->debug ) wire('log')->save("process_sync", "File uploaded to S3: {$system_path}"); | |
} | |
} | |
catch (Exception $e){ | |
throw new WireException("Error: Image variation not added to S3: {$e->getMessage()}"); | |
} | |
} | |
//https://processwire.com/blog/posts/pw-3.0.137/ | |
public function downloadImageServer($event){ | |
$config = $event->wire('config'); | |
$file = $event->return; | |
if($event->method == 'url') { | |
// convert url to disk path | |
$file = $config->paths->root . substr($file, strlen($config->urls->root)); | |
} | |
if( !file_exists($file) ) { | |
// download file from source if it doesn't exist here | |
$src = '[YOUR-PRODUCTION-URL]/site/assets/files/'; | |
$url = str_replace($config->paths->files, $src, $file); | |
$http = new WireHttp(); | |
$http->download($url, $file); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment