How can I change wordpress attachment url and protect it?

I was confused by one thing, because WordPress attachment URL is directly to see and for download, I want to hide it and make it transfer by one file so I can add some control for this file. If I use a plugin named User-access-manager(UAM) to control all page/post access.

e.g:

http://wordpressxxx.com/private-one/wp-content/uploads/sites/6/2015/01/GCC-manual.pdf

transfer to

http://wordpressxxx.com/private-one/download.php?id=xxx

(private-one is one of wordpress network multisites.)

I query manual, it seems like I should change attachment data when file data was inserted into DB. because the PAGE/POST was inserted to the attachment database directly. When one page has an attachment that was posted, the attachment URL can’t be changed again because it was written into the database.

I use add_filter in my plugin for wp_insert_attachment and wp_insert_attachment_data, but I can’t get the attachment post data so I can’t modify it.

Here are my assumed steps:

  1. change the attachment post data when add a new media.
  2. build a database table to store the key=>value, key is the attachment_id, value is the unique id which can be used in http://wordpressxxx.com/private-one/download.php?id=
  3. add query WordPress role/capability in download.php and control this file access

Do you have any idea about this?

1 Answer
1

I’ve figured out a solution, here is my answer

1, we can’t modify WordPress original data input, but we can modify and rewrite the output. So we can use the_content,wp_get_attachment_url to change this.

add this code snippets into your plugins

    if (function_exists('add_filter')) {

        add_filter('the_content', array($scplugin, 'AttachmentRewrite'), 10, 1);
        add_filter('wp_get_attachment_url', array($scplugin, 'AttachmentUrlRewrite'), 10, 1);
    }

the ‘$scplugin’ is my plugin class. ‘the_content’ filter will pass a “the content” string into ‘AttachmentRewrite’ function. so does the ‘wp_get_attachment_url’, but it will pass a url string.

then we can modify and rewrite the content url link by regex.

here is the AttachmentRewrite function code snippets:

/**
 * Rewrite the content attachment links.
 *
 * @param string $content theContent.
 *
 * @return mix.
 */
public function AttachmentRewrite($content)
{
    $pattern = "/<a href=\"(\S+)(\/wp-content\/uploads\/sites\/)([0-9]+)(\S+)\">/";
    preg_match_all($pattern, $content, $match);

    // $match[0]  all links
    // $match[1] link head  http://xxx/network site subpath
    // $match[2] replace content /wp-content/uploads/sites/
    // $match[3] site num
    // $match[4] file meta_value
    if (isset($match) && is_array($match)) {
        $post_id = get_the_ID();
        $old_links = array();
        $new_links = array();
        foreach ($match[1] as $k => $v) {
            $old_links[$k] = $v.$match[2][$k].$match[3][$k].$match[4][$k];
            $checkMedia = $this->QueryMediaMeta($match[3][$k], $match[4][$k]);

            if (!$checkMedia) {
                $new_links[$k] = $old_links[$k];
            } else {
                if (isset($checkMedia['post_type']) && $checkMedia['post_type'] == 'attachment' && isset($checkMedia['post_mime_type']) ) {
                    $checkApp = strpos($checkMedia['post_mime_type'], 'application');

                    if ($checkApp === false) {
                        $new_links[$k] = $old_links[$k];
                    } else {
                        $_snx_id = $this->UpdateAttachUrl($match[3][$k], $match[4][$k]);
                        $rand_string = $this->RandString(10);
                        // s=site no, id=snx attachment_id, aid=post type attachment type id
                        $param = $rand_string.base64_encode('s=".$match[3][$k]."&id='.$_snx_id.'&p='.$post_id);
                        // return $match[1].'/download.php?s=".$match[3][$k]."&id='.$_snx_id;
                        $new_links[$k] = $v.'/download.php?fid='.$param;
                    }
                } else {
                    $new_links[$k] = $old_links[$k];
                }
            }
            //$new_links[$k] = array_walk($_head_link, array($this, '_array_walks')).'?download.php?s=".$match[3][$k]."&id='.$match[4][$k];
        }
        array_walk($old_links, array($this, 'snxArrayWalks'));
        $content = preg_replace($old_links, $new_links, $content);
    }

    return $content;
}

I use preg_match_all to match all attachment url, including the media(mp3,jpeg,gif). then we wget the match data, but we will filter it again for the mp3,jpeg,gif etc, so the function QueryMediaMeta will query wp_posts and wp_post_meta by filename and site num to get this.

Then I use a RandString and base64_encode to translate the original url. and return the new the_content data.

In the download.php, you can control the access right, define forbidden page. etc.

Leave a Comment