add_filter('wp_calculate_image_srcset', array($this, 'calculate_image_srcset'), 10, 2);
// <===== 2017-08-11 fukushima
// update S3 object
add_action('edit_attachment', array($this, 'edit_attachment'));
add_action('add_attachment', array($this, 'add_attachment'));
// delete S3 object
add_action('delete_attachment', array($this, 'delete_attachment'));
}
static public function plugin_basename() {
return plugin_basename(dirname(dirname(__FILE__)).'/plugin.php');
}
// the_content filter hook
public function the_content($content){
$post_id = intval(get_the_ID());
remove_filter('wp_get_attachment_url', array($this, 'get_attachment_url'), 10, 2);
$content = $this->replace_s3_url($content, $post_id);
add_filter('wp_get_attachment_url', array($this, 'get_attachment_url'), 10, 2);
return $content;
}
// widget_text filter hook
public function widget_text($content){
remove_filter('wp_get_attachment_url', array($this, 'get_attachment_url'), 10, 2);
$content = $this->replace_s3_url($content, false);
add_filter('wp_get_attachment_url', array($this, 'get_attachment_url'), 10, 2);
return $content;
}
// wp_get_attachment_url filter hook
public function get_attachment_url($url, $post_id = null) {
static $urls = array();
if (!isset($post_id))
$post_id = get_the_ID();
$post_id = intval($post_id);
if (isset($urls[$post_id]))
return $urls[$post_id];
remove_filter('wp_get_attachment_url', array($this, 'get_attachment_url'), 10, 2);
$url = $this->replace_s3_url($url, $post_id);
add_filter('wp_get_attachment_url', array($this, 'get_attachment_url'), 10, 2);
$urls[$post_id] = $url;
return $url;
}
// 2017-08-11 fukushima =====>
// wp_calculate_image_srcset filter hook
public function calculate_image_srcset( $sources ) {
remove_filter('wp_calculate_image_srcset', array($this, 'calculate_image_srcset'), 10, 2);
foreach ($sources as $key => $value) {
$url = $value['url'];
$pattern = '@https?:\/\/[^\/]+/@';
$s3_url = isset(self::$options['s3_url']) ? self::$options['s3_url'] : false;
if ($s3_url) {
$replaced_url = preg_replace($pattern, $s3_url . '/', $url);
$sources[$key]['url'] = $replaced_url;
}
}
add_filter('wp_calculate_image_srcset', array($this, 'calculate_image_srcset'), 10, 2);
return $sources;
}
// <===== 2017-08-11 fukushima
public function edit_attachment($attachment_id){
return $this->add_attachment($attachment_id, true);
}
public function add_attachment($attachment_id, $force = false){
$post = get_post($attachment_id);
if ($post->post_type !== 'attachment')
return;
$attachment_meta_key = self::META_KEY;
$s3_bucket = isset(self::$options['bucket']) ? self::$options['bucket'] : false;
$s3_url = isset(self::$options['s3_url']) ? self::$options['s3_url'] : false;
$storage_class = isset(self::$options['storage_class']) ? self::$options['storage_class'] : 'STANDARD';
// object upload to S3
if ( !$force ) {
$S3_medias_new = $this->get_s3_media_info($attachment_id);
$S3_medias_old = get_post_meta($attachment_id, $attachment_meta_key, true);
if (is_array($S3_medias_old)) {
if (isset($S3_medias_old[$s3_bucket]))
$S3_medias_old = (array)$S3_medias_old[$s3_bucket];
} else {
$S3_medias_old = array();
}
} else {
$S3_medias_new = $this->get_s3_media_info($post_id);
$S3_medias_old = array();
}
if ($force || $S3_medias_new !== $S3_medias_old) {
$S3_medias = array();
foreach($S3_medias_new as $size => $val ) {
if ($force || !isset($S3_medias_old[$size])) {
$result = $this->s3_upload($val['file'], $s3_bucket, $val['s3_key'], $storage_class);
$S3_medias[$size] = $val;
}
if (!file_exists($val['file'])) {
$this->s3_download($val['file'], $s3_bucket, $val['s3_key']);
}
}
$S3_medias_old = get_post_meta($attachment_id, $attachment_meta_key, true);
if (is_array($S3_medias_old)) {
$S3_medias_old[$s3_bucket] = $S3_medias;
$S3_medias = $S3_medias_old;
} else {
$S3_medias = array($s3_bucket => $S3_medias);
}
update_post_meta($attachment_id, $attachment_meta_key, $S3_medias);
}
}
// delete_attachment action hook
public function delete_attachment($post_id){
$post = get_post($post_id);
if ($post->post_type !== 'attachment')
return;
if ($all_S3_medias = get_post_meta($post_id, self::META_KEY, true)){
foreach ($all_S3_medias as $S3_bucket => $S3_medias) {
foreach ($S3_medias as $S3_media) {
$this->s3_delete($S3_bucket, $S3_media['s3_key']);
}
}
}
unset($all_S3_medias);
}
// Replace URL
private function replace_s3_url($content, $post_id){
global $pagenow;
// When logged in, do not rewrite the path to s3. 2017-12-01 fukushima
if ( is_user_logged_in() )
return $content;
if (empty($content))
return $content;
$s3_bucket = isset(self::$options['bucket']) ? self::$options['bucket'] : false;
$s3_url = isset(self::$options['s3_url']) ? self::$options['s3_url'] : false;
$storage_class = isset(self::$options['storage_class']) ? self::$options['storage_class'] : false;
if (!$s3_bucket || !$s3_url)
return $content;
// get attachments
$attachment_meta_key = self::META_KEY;
$post_meta_key = self::META_KEY.'-replace';
if ($post_id) {
if ($replace_data = get_post_meta($post_id, $post_meta_key, true)) {
$replace_data_org = isset($replace_data[$s3_bucket]) ? $replace_data[$s3_bucket] : array();
foreach($replace_data_org as $search_url => $replace_url){
$content = str_replace($search_url, $replace_url, $content);
}
}
$attachments = $this->get_post_attachments($post_id, $content);
if (self::DEBUG_MODE && function_exists('dbgx_trace_var')) {
dbgx_trace_var($post_id);
dbgx_trace_var($attachments);
}
if (!$attachments) {
return $content;
}
} else {
$attachments_count = 0;
$medias = array();
$attachments = $this->get_post_attachments_from_content($content, $attachments_count, $medias);
if (self::DEBUG_MODE && function_exists('dbgx_trace_var')) {
dbgx_trace_var($attachments);
}
if (!$attachments) {
return $content;
}
}
// object upload to S3, and replace url
$replace_count = 0;
$replace_data = array();
$attachments_meta = array();
foreach ($attachments as $attachment) {
$S3_medias_new = $this->get_s3_media_info($attachment->ID);
$S3_medias_old = get_post_meta($attachment->ID, $attachment_meta_key, true);
if (is_array($S3_medias_old)) {
if (isset($S3_medias_old[$s3_bucket]))
$S3_medias_old = (array)$S3_medias_old[$s3_bucket];
} else {
$S3_medias_old = array();
}
if (self::DEBUG_MODE && function_exists('dbgx_trace_var')) {
dbgx_trace_var($S3_medias_new);
dbgx_trace_var($S3_medias_old);
}
if ($S3_medias_new !== $S3_medias_old) {
$S3_medias = array();
foreach($S3_medias_new as $size => $val ) {
$replace_flag = true;
$search_url = $val['url'];
$replace_url = $s3_url . $val['s3_key'];
if (!isset($S3_medias_old[$size])) {
$result = $this->s3_upload($val['file'], $s3_bucket, $val['s3_key'], $storage_class);
$replace_flag = !$result ? false : true;
if (self::DEBUG_MODE && function_exists('dbgx_trace_var')) {
dbgx_trace_var($result);
dbgx_trace_var($val);
}
}
if ($replace_flag && $search_url && $replace_url) {
$S3_medias[$size] = $val;
if (!isset($replace_data[$search_url]) && (!is_admin() || $pagenow === 'upload.php')) {
$replace_data[$search_url] = $replace_url;
$content = str_replace($search_url, $replace_url, $content);
}
}
if (!file_exists($val['file']))
$this->s3_download($val['file'], $s3_bucket, $val['s3_key']);
}
if (self::DEBUG_MODE && function_exists('dbgx_trace_var')) {
dbgx_trace_var($S3_medias);
}
if (count($S3_medias) > 0 && $S3_medias !== $S3_medias_old)
update_post_meta($attachment->ID, $attachment_meta_key, array($s3_bucket => $S3_medias));
// 2017-03-01 fukushima -->
// I also want to download a media file from AWS s3 in a call from admin-ajax.php.
} else if (!is_admin() || $pagenow === 'upload.php' || $pagenow === 'admin-ajax.php') {
// } else if (!is_admin() || $pagenow === 'upload.php') {
// <-- 2017-03-01 fukushima
foreach($S3_medias_new as $size => $val ) {
$search_url = $val['url'];
$replace_url = $s3_url . $val['s3_key'];
if (!isset($replace_data[$search_url])) {
$replace_data[$search_url] = $replace_url;
$content = str_replace($search_url, $replace_url, $content);
}
if (!file_exists($val['file']))
$this->s3_download($val['file'], $s3_bucket, $val['s3_key']);
}
}
$replace_count++;
}
if (self::DEBUG_MODE && function_exists('dbgx_trace_var')) {
dbgx_trace_var($replace_data);
dbgx_trace_var($replace_data_org);
}
if ($post_id && ($replace_data !== $replace_data_org))
update_post_meta($post_id, $post_meta_key, array($s3_bucket => $replace_data));
unset($S3_medias_new);
unset($S3_medias_old);
unset($S3_medias);
return $content;
}
// Initializing S3 object
private function s3($S3_bucket = null){
if (isset(self::$s3)) {
if (isset($S3_bucket) && self::$s3->current_bucket() !== $S3_bucket)
self::$s3->set_current_bucket($S3_bucket);
return self::$s3;
}
if (self::$options) {
$s3 = Argiope_S3_Helper::get_instance();
$s3->init(
isset(self::$options['access_key']) ? self::$options['access_key'] : null,
isset(self::$options['secret_key']) ? self::$options['secret_key'] : null,
isset(self::$options['region']) ? self::$options['region'] : null
);
if ($s3 && isset($S3_bucket))
$s3->set_current_bucket($S3_bucket);
self::$s3 = $s3;
return $s3;
}
return false;
}
// Upload file to S3
private function s3_upload($filename, $S3_bucket, $S3_key, $storage_class){
if (!file_exists($filename))
return false;
$upload_result = false;
if ($s3 = $this->s3($S3_bucket)) {
if ($s3->object_exists($S3_key))
return true;
$upload_result = $s3->upload($filename, $S3_key, null, $storage_class);
}
return $upload_result;
}
// Download file to S3
private function s3_download($filename, $S3_bucket, $S3_key){
$download_result = false;
if ($s3 = $this->s3($S3_bucket)) {
if (!$s3->object_exists($S3_key))
return false;
$download_result = $s3->download($S3_key, $filename);
}
return $download_result;
}
// Delete S3 object
private function s3_delete($S3_bucket, $S3_key){
$delete_result = false;
if ($s3 = $this->s3($S3_bucket)) {
$delete_result =
$s3->object_exists($S3_key)
? $s3->delete($S3_key)
: true;
}
return $delete_result;
}
// Get post attachments
private function get_post_attachments($post, $content = false) {
static $post_meta = array();
if (is_numeric($post)) {
$post_id = $post;
$post = get_post($post_id);
$post_type = $post->post_type;
} else if (is_object($post)) {
$post_id = $post->ID;
$post_type = $post->post_type;
} else {
return false;
}
$attachments = array();
$attachments_count = 0;
if ($post_type === 'attachment') {
$attachments[] = $post;
$attachments_count = 1;
} else {
// Get post attachments from media library
$medias = array();
if ($attachments = get_posts(array('post_type' => 'attachment', 'post_parent' => $post_id))) {
$upload_dir = wp_upload_dir();
foreach($attachments as $attachment) {
$attachment_file = str_replace($upload_dir['baseurl'].'/', '', $attachment->guid);
$medias[] = $attachment_file;
}
} else {
$attachments = array();
}
// Get post attachments from post content
if ($content) {
$wk_attachments = $this->get_post_attachments_from_content($content, $attachments_count, $medias);
$attachments = array_merge($attachments, $wk_attachments);
unset($wk_attachments);
}
unset($medias);
$attachments_count = count($attachments);
}
$post_meta[$post_id] = $attachments_count > 0 ? $attachments : false;
return $post_meta[$post_id];
}
// Get post attachments from post content
private function get_post_attachments_from_content($content, &$attachments_count, &$medias) {
$attachments = array();
$upload_dir = wp_upload_dir();
$img_src_pattern = array(
'#]*href=[\'"]'.preg_quote($upload_dir['baseurl']).'/([^\'"]*)[\'"][^>]*>
]*>#ism',
'#
]*src=[\'"]'.preg_quote($upload_dir['baseurl']).'/([^\'"]*)[\'"][^>]*>#ism',
);
$img_src_pattern = (array)apply_filters('Argiope_Amoena/img_src_pattern', $img_src_pattern);
foreach ($img_src_pattern as $pattern) {
if (preg_match_all($pattern, $content, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
if ($attachments_count > self::LIMIT)
break;
if ($attachment = $this->get_attachment_from_filename($match[1], $medias)) {
$attachments[] = $attachment;
$attachments_count++;
}
}
}
unset($matches);
}
return count($attachments) > 0 ? $attachments : array();
}
// Get attachment from file name
private function get_attachment_from_filename($attachment_file, &$medias = array()){
global $wpdb;
if (!isset($medias))
$medias = array();
if (!is_array($medias))
$medias = (array)$medias;
$attachment_file = preg_replace('#\.(png|gif|jpe?g)\?[^\?]*$#uism','.$1',$attachment_file);
$attachment_file = preg_replace('#^(.*[^/])\-[0-9]+x[0-9]+\.(png|gif|jpe?g)([\?]?.*)$#uism','$1.$2',$attachment_file);
if ($attachment_file && in_array($attachment_file, $medias))
return false;
$medias[] = $attachment_file;
$attachment = $wpdb->get_row($wpdb->prepare("
select p.* from {$wpdb->posts} as p inner join {$wpdb->postmeta} as m on p.ID = m.post_id
where m.meta_key = %s and m.meta_value = %s limit 1",
'_wp_attached_file',
$attachment_file));
return $attachment;
}
// Get attachment sizes
private function get_attachment_sizes($attachment_id){
$imagedata = wp_get_attachment_metadata($attachment_id);
$sizes = array_merge(array('normal'), isset($imagedata['sizes']) ? array_keys($imagedata['sizes']) : array());
return $sizes;
}
// Get media file info
private function get_s3_media_info($attachment_id) {
$sizes = $this->get_attachment_sizes($attachment_id);
$images = array();
foreach ($sizes as $size) {
$upload_dir_config = wp_upload_dir();
$content_path = $upload_dir_config['basedir'];
$content_url = $upload_dir_config['baseurl'];
if ( $image_src = wp_get_attachment_image_src($attachment_id, $size) ) {
$images[$size] = array(
'url' => $image_src[0],
'file' => str_replace($content_url, $content_path, $image_src[0]),
's3_key' => preg_replace('#https?://[^/]*/#i', '/', $image_src[0]),
);
} elseif ($attachment_url = wp_get_attachment_url($attachment_id, $size) ) {
$images[$size] = array(
'url' => $attachment_url,
'file' => str_replace($content_url, $content_path, $attachment_url),
's3_key' => preg_replace('#https?://[^/]*/#i', '/', $attachment_url),
);
}
}
return $images;
}
}