Skip to content

Commit 1229132

Browse files
authored
Merge pull request #133 from cloudinary/feature/unique-filesnames
Feature/unique-filenames
2 parents a4812af + 97a564e commit 1229132

File tree

4 files changed

+202
-42
lines changed

4 files changed

+202
-42
lines changed

cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-media.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,11 @@ public function get_public_id( $attachment_id ) {
655655
public function get_cloudinary_id( $attachment_id ) {
656656

657657
// A cloudinary_id is a public_id with a file extension.
658-
$public_id = $this->get_public_id( $attachment_id );
658+
$public_id = $this->get_public_id( $attachment_id );
659+
$suffix_data = $this->get_post_meta( $attachment_id, Sync::META_KEYS['suffix'], true );
660+
if ( is_array( $suffix_data ) && ! empty( $suffix_data['suffix'] ) && $suffix_data['public_id'] === $public_id ) {
661+
$public_id = $public_id . $suffix_data['suffix'];
662+
}
659663
$file = get_attached_file( $attachment_id );
660664
$info = pathinfo( $file );
661665
$cloudinary_id = $public_id . '.' . $info['extension'];

cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-sync.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class Sync implements Setup, Assets {
4949
'sync_error' => '_sync_error',
5050
'cloudinary' => '_cloudinary_v2',
5151
'folder_sync' => '_folder_sync',
52+
'suffix' => '_suffix',
5253
'syncing' => '_cloudinary_syncing',
5354
'downloading' => '_cloudinary_downloading',
5455
);
@@ -172,13 +173,85 @@ public function get_signature( $post_id ) {
172173
return $return;
173174
}
174175

176+
/**
177+
* Generate a new Public ID for an asset.
178+
*
179+
* @param int $attachment_id The attachment ID for the new public ID.
180+
*
181+
* @return string|null
182+
*/
183+
public function generate_public_id( $attachment_id ) {
184+
$settings = $this->plugin->config['settings'];
185+
$cld_folder = trailingslashit( $settings['sync_media']['cloudinary_folder'] );
186+
$file = get_attached_file( $attachment_id );
187+
$file_info = pathinfo( $file );
188+
$public_id = $cld_folder . $file_info['filename'];
189+
190+
return $public_id;
191+
}
192+
193+
/**
194+
* Maybe add a suffix to the public ID if it's not unique.
195+
*
196+
* @param string $public_id The public ID to maybe add a suffix.
197+
* @param int $attachment_id The attachment ID.
198+
* @param string|null $suffix The suffix to maybe add.
199+
*
200+
* @return string The public ID.
201+
*/
202+
public function add_suffix_maybe( $public_id, $attachment_id, $suffix = null ) {
203+
204+
// Test if asset exists by calling just the head on the asset url, to prevent API rate limits.
205+
$url = $this->plugin->components['connect']->api->cloudinary_url( $public_id . $suffix );
206+
$req = wp_remote_head( $url, array( 'body' => array( 'rdm' => wp_rand( 100, 999 ) ) ) );
207+
$asset_error = strtolower( wp_remote_retrieve_header( $req, 'x-cld-error' ) );
208+
$code = wp_remote_retrieve_response_code( $req );
209+
210+
// If the request is not a 404 & does not have a cld-error header stating resource not found, it exists and should be checked that it's not a resync or generate a prefixed ID.
211+
if ( 404 !== $code && false === strpos( $asset_error, 'resource not found' ) ) {
212+
213+
// Get the attachment type.
214+
if ( wp_attachment_is( 'image', $attachment_id ) ) {
215+
$type = 'image';
216+
} elseif ( wp_attachment_is( 'video', $attachment_id ) ) {
217+
$type = 'video';
218+
} elseif ( wp_attachment_is( 'audio', $attachment_id ) ) {
219+
$type = 'audio';
220+
} else {
221+
// not supported.
222+
return null;
223+
}
224+
$cld_asset = $this->plugin->components['connect']->api->get_asset_details( $public_id, $type );
225+
if ( ! is_wp_error( $cld_asset ) && ! empty( $cld_asset['public_id'] ) ) {
226+
$context_id = null;
227+
228+
// Exists, check to see if this asset originally belongs to this ID.
229+
if ( ! empty( $cld_asset['context'] ) && ! empty( $cld_asset['context']['custom'] ) && ! empty( $cld_asset['context']['custom']['wp_id'] ) ) {
230+
$context_id = (int) $cld_asset['context']['custom']['wp_id'];
231+
}
232+
233+
// Generate new ID only if context ID is not related.
234+
if ( $context_id !== $attachment_id ) {
235+
// Generate a new ID with a uniqueID prefix.
236+
$suffix = '-' . uniqid();
237+
238+
// Return new potential suffixed ID.
239+
return $this->add_suffix_maybe( $public_id, $attachment_id, $suffix );
240+
}
241+
}
242+
}
243+
244+
return $suffix;
245+
}
246+
175247
/**
176248
* Additional component setup.
177249
*/
178250
public function setup() {
179251
if ( $this->plugin->config['connect'] ) {
180252
$this->managers['upload']->setup();
181253
$this->managers['delete']->setup();
254+
$this->managers['push']->setup();
182255
}
183256
}
184257
}

cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/connect/class-api.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,20 @@ public function cloudinary_url( $public_id, $args = array(), $size = array(), $c
269269
return implode( '/', $url_parts );
270270
}
271271

272+
/**
273+
* Get the details of an asset by public ID.
274+
*
275+
* @param string $public_id The public_id to check.
276+
* @param string $type The asset type.
277+
*
278+
* @return array|\WP_Error
279+
*/
280+
public function get_asset_details( $public_id, $type ) {
281+
$url = $this->url( 'resources', $type . '/upload/' . $public_id, true );
282+
283+
return $this->call( $url, array( 'body' => $args ), 'get' );
284+
}
285+
272286
/**
273287
* Upload a large asset in chunks.
274288
*

0 commit comments

Comments
 (0)